Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f23f723

Browse files
committed
Merge branch 'main' of https://github.com/coder/coder into bq/replace-mui-icons-3
2 parents 55bc70f + b0a4ef0 commit f23f723

File tree

47 files changed

+809
-523
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+809
-523
lines changed

.github/workflows/weekly-docs.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
reporter: github-pr-review
3737
config_file: ".github/.linkspector.yml"
3838
fail_on_error: "true"
39-
filter_mode: "nofilter"
39+
filter_mode: "file"
4040

4141
- name: Send Slack notification
4242
if: failure() && github.event_name == 'schedule'

cli/update_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ func TestUpdateValidateRichParameters(t *testing.T) {
757757
err := inv.Run()
758758
// TODO: improve validation so we catch this problem before it reaches the server
759759
// but for now just validate that the server actually catches invalid monotonicity
760-
assert.ErrorContains(t, err, fmt.Sprintf("parameter value must be equal or greater than previous value: %s", tempVal))
760+
assert.ErrorContains(t, err, "parameter value '1' must be equal or greater than previous value: 2")
761761
}()
762762

763763
matches := []string{

coderd/testdata/parameters/groups/main.tf

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ data "coder_parameter" "group" {
1212
name = "group"
1313
default = try(data.coder_workspace_owner.me.groups[0], "")
1414
dynamic "option" {
15-
for_each = data.coder_workspace_owner.me.groups
15+
for_each = concat(data.coder_workspace_owner.me.groups, "bloob")
1616
content {
1717
name = option.value
1818
value = option.value

codersdk/richparameters.go

+14-32
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package codersdk
22

33
import (
4-
"strconv"
5-
64
"golang.org/x/xerrors"
5+
"tailscale.com/types/ptr"
76

87
"github.com/coder/terraform-provider-coder/v2/provider"
98
)
@@ -46,47 +45,31 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui
4645
}
4746

4847
func validateBuildParameter(richParameter TemplateVersionParameter, buildParameter *WorkspaceBuildParameter, lastBuildParameter *WorkspaceBuildParameter) error {
49-
var value string
48+
var (
49+
current string
50+
previous *string
51+
)
5052

5153
if buildParameter != nil {
52-
value = buildParameter.Value
54+
current = buildParameter.Value
5355
}
5456

55-
if richParameter.Required && value == "" {
56-
return xerrors.Errorf("parameter value is required")
57+
if lastBuildParameter != nil {
58+
previous = ptr.To(lastBuildParameter.Value)
5759
}
5860

59-
if value == "" { // parameter is optional, so take the default value
60-
value = richParameter.DefaultValue
61+
if richParameter.Required && current == "" {
62+
return xerrors.Errorf("parameter value is required")
6163
}
6264

63-
if lastBuildParameter != nil && lastBuildParameter.Value != "" && richParameter.Type == "number" && len(richParameter.ValidationMonotonic) > 0 {
64-
prev, err := strconv.Atoi(lastBuildParameter.Value)
65-
if err != nil {
66-
return xerrors.Errorf("previous parameter value is not a number: %s", lastBuildParameter.Value)
67-
}
68-
69-
current, err := strconv.Atoi(buildParameter.Value)
70-
if err != nil {
71-
return xerrors.Errorf("current parameter value is not a number: %s", buildParameter.Value)
72-
}
73-
74-
switch richParameter.ValidationMonotonic {
75-
case MonotonicOrderIncreasing:
76-
if prev > current {
77-
return xerrors.Errorf("parameter value must be equal or greater than previous value: %d", prev)
78-
}
79-
case MonotonicOrderDecreasing:
80-
if prev < current {
81-
return xerrors.Errorf("parameter value must be equal or lower than previous value: %d", prev)
82-
}
83-
}
65+
if current == "" { // parameter is optional, so take the default value
66+
current = richParameter.DefaultValue
8467
}
8568

8669
if len(richParameter.Options) > 0 {
8770
var matched bool
8871
for _, opt := range richParameter.Options {
89-
if opt.Value == value {
72+
if opt.Value == current {
9073
matched = true
9174
break
9275
}
@@ -95,7 +78,6 @@ func validateBuildParameter(richParameter TemplateVersionParameter, buildParamet
9578
if !matched {
9679
return xerrors.Errorf("parameter value must match one of options: %s", parameterValuesAsArray(richParameter.Options))
9780
}
98-
return nil
9981
}
10082

10183
if !validationEnabled(richParameter) {
@@ -119,7 +101,7 @@ func validateBuildParameter(richParameter TemplateVersionParameter, buildParamet
119101
Error: richParameter.ValidationError,
120102
Monotonic: string(richParameter.ValidationMonotonic),
121103
}
122-
return validation.Valid(richParameter.Type, value)
104+
return validation.Valid(richParameter.Type, current, previous)
123105
}
124106

125107
func findBuildParameter(params []WorkspaceBuildParameter, parameterName string) (*WorkspaceBuildParameter, bool) {

docs/admin/templates/extending-templates/parameters.md

+13-13
Original file line numberDiff line numberDiff line change
@@ -374,20 +374,20 @@ data "coder_parameter" "jetbrains_ide" {
374374
## Create Autofill
375375
376376
When the template doesn't specify default values, Coder may still autofill
377-
parameters.
377+
parameters in one of two ways:
378378
379-
You need to enable `auto-fill-parameters` first:
379+
- Coder will look for URL query parameters with form `param.<name>=<value>`.
380380
381-
```shell
382-
coder server --experiments=auto-fill-parameters
383-
```
381+
This feature enables platform teams to create pre-filled template creation links.
382+
383+
- Coder can populate recently used parameter key-value pairs for the user.
384+
This feature helps reduce repetition when filling common parameters such as
385+
`dotfiles_url` or `region`.
386+
387+
To enable this feature, you need to set the `auto-fill-parameters` experiment flag:
384388
385-
Or set the [environment variable](../../setup/index.md), `CODER_EXPERIMENTS=auto-fill-parameters`
386-
With the feature enabled:
389+
```shell
390+
coder server --experiments=auto-fill-parameters
391+
```
387392
388-
1. Coder will look for URL query parameters with form `param.<name>=<value>`.
389-
This feature enables platform teams to create pre-filled template creation
390-
links.
391-
2. Coder will populate recently used parameter key-value pairs for the user.
392-
This feature helps reduce repetition when filling common parameters such as
393-
`dotfiles_url` or `region`.
393+
Or set the [environment variable](../../setup/index.md), `CODER_EXPERIMENTS=auto-fill-parameters`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# Prebuilt workspaces
2+
3+
Prebuilt workspaces allow template administrators to improve the developer experience by reducing workspace
4+
creation time with an automatically maintained pool of ready-to-use workspaces for specific parameter presets.
5+
6+
The template administrator configures a template to provision prebuilt workspaces in the background, and then when a developer creates
7+
a new workspace that matches the preset, Coder assigns them an existing prebuilt instance.
8+
Prebuilt workspaces significantly reduce wait times, especially for templates with complex provisioning or lengthy startup procedures.
9+
10+
Prebuilt workspaces are:
11+
12+
- Created and maintained automatically by Coder to match your specified preset configurations.
13+
- Claimed transparently when developers create workspaces.
14+
- Monitored and replaced automatically to maintain your desired pool size.
15+
16+
## Relationship to workspace presets
17+
18+
Prebuilt workspaces are tightly integrated with [workspace presets](./parameters.md#workspace-presets-beta):
19+
20+
1. Each prebuilt workspace is associated with a specific template preset.
21+
1. The preset must define all required parameters needed to build the workspace.
22+
1. The preset parameters define the base configuration and are immutable once a prebuilt workspace is provisioned.
23+
1. Parameters that are not defined in the preset can still be customized by users when they claim a workspace.
24+
25+
## Prerequisites
26+
27+
- [**Premium license**](../../licensing/index.md)
28+
- **Compatible Terraform provider**: Use `coder/coder` Terraform provider `>= 2.4.0`.
29+
- **Feature flag**: Enable the `workspace-prebuilds` [experiment](../../../reference/cli/server.md#--experiments).
30+
31+
## Enable prebuilt workspaces for template presets
32+
33+
In your template, add a `prebuilds` block within a `coder_workspace_preset` definition to identify the number of prebuilt
34+
instances your Coder deployment should maintain:
35+
36+
```hcl
37+
data "coder_workspace_preset" "goland" {
38+
name = "GoLand: Large"
39+
parameters = {
40+
jetbrains_ide = "GO"
41+
cpus = 8
42+
memory = 16
43+
}
44+
prebuilds {
45+
instances = 3 # Number of prebuilt workspaces to maintain
46+
}
47+
}
48+
```
49+
50+
After you publish a new template version, Coder will automatically provision and maintain prebuilt workspaces through an
51+
internal reconciliation loop (similar to Kubernetes) to ensure the defined `instances` count are running.
52+
53+
## Prebuilt workspace lifecycle
54+
55+
Prebuilt workspaces follow a specific lifecycle from creation through eligibility to claiming.
56+
57+
1. After you configure a preset with prebuilds and publish the template, Coder provisions the prebuilt workspace(s).
58+
59+
1. Coder automatically creates the defined `instances` count of prebuilt workspaces.
60+
1. Each new prebuilt workspace is initially owned by an unprivileged system pseudo-user named `prebuilds`.
61+
- The `prebuilds` user belongs to the `Everyone` group (you can add it to additional groups if needed).
62+
1. Each prebuilt workspace receives a randomly generated name for identification.
63+
1. The workspace is provisioned like a regular workspace; only its ownership distinguishes it as a prebuilt workspace.
64+
65+
1. Prebuilt workspaces start up and become eligible to be claimed by a developer.
66+
67+
Before a prebuilt workspace is available to users:
68+
69+
1. The workspace is provisioned.
70+
1. The agent starts up and connects to coderd.
71+
1. The agent starts its bootstrap procedures and completes its startup scripts.
72+
1. The agent reports `ready` status.
73+
74+
After the agent reports `ready`, the prebuilt workspace considered eligible to be claimed.
75+
76+
Prebuilt workspaces that fail during provisioning are retried with a backoff to prevent transient failures.
77+
78+
1. When a developer requests a new workspace, the claiming process occurs:
79+
80+
1. Developer selects a template and preset that has prebuilt workspaces configured.
81+
1. If an eligible prebuilt workspace exists, ownership transfers from the `prebuilds` user to the requesting user.
82+
1. The workspace name changes to the user's requested name.
83+
1. `terraform apply` is executed using the new ownership details, which may affect the [`coder_workspace`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace) and
84+
[`coder_workspace_owner`](https://registry.terraform.io/providers/coder/coder/latest/docs/data-sources/workspace_owner)
85+
datasources (see [Preventing resource replacement](#preventing-resource-replacement) for further considerations).
86+
87+
The developer doesn't see the claiming process — the workspace will just be ready faster than usual.
88+
89+
You can view available prebuilt workspaces in the **Workspaces** view in the Coder dashboard:
90+
91+
![A prebuilt workspace in the dashboard](../../../images/admin/templates/extend-templates/prebuilt/prebuilt-workspaces.png)
92+
_Note the search term `owner:prebuilds`._
93+
94+
### Template updates and the prebuilt workspace lifecycle
95+
96+
Prebuilt workspaces are not updated after they are provisioned.
97+
98+
When a template's active version is updated:
99+
100+
1. Prebuilt workspaces for old versions are automatically deleted.
101+
1. New prebuilt workspaces are created for the active template version.
102+
1. If dependencies change (e.g., an [AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) update) without a template version change:
103+
- You may delete the existing prebuilt workspaces manually.
104+
- Coder will automatically create new prebuilt workspaces with the updated dependencies.
105+
106+
The system always maintains the desired number of prebuilt workspaces for the active template version.
107+
108+
## Administration and troubleshooting
109+
110+
### Managing resource quotas
111+
112+
Prebuilt workspaces can be used in conjunction with [resource quotas](../../users/quotas.md).
113+
Because unclaimed prebuilt workspaces are owned by the `prebuilds` user, you can:
114+
115+
1. Configure quotas for any group that includes this user.
116+
1. Set appropriate limits to balance prebuilt workspace availability with resource constraints.
117+
118+
If a quota is exceeded, the prebuilt workspace will fail provisioning the same way other workspaces do.
119+
120+
### Template configuration best practices
121+
122+
#### Preventing resource replacement
123+
124+
When a prebuilt workspace is claimed, another `terraform apply` run occurs with new values for the workspace owner and name.
125+
126+
This can cause issues in the following scenario:
127+
128+
1. The workspace is initially created with values from the `prebuilds` user and a random name.
129+
1. After claiming, various workspace properties change (ownership, name, and potentially other values), which Terraform sees as configuration drift.
130+
1. If these values are used in immutable fields, Terraform will destroy and recreate the resource, eliminating the benefit of prebuilds.
131+
132+
For example, when these values are used in immutable fields like the AWS instance `user_data`, you'll see resource replacement during claiming:
133+
134+
![Resource replacement notification](../../../images/admin/templates/extend-templates/prebuilt/replacement-notification.png)
135+
136+
To prevent this, add a `lifecycle` block with `ignore_changes`:
137+
138+
```hcl
139+
resource "docker_container" "workspace" {
140+
lifecycle {
141+
ignore_changes = all
142+
}
143+
144+
count = data.coder_workspace.me.start_count
145+
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
146+
...
147+
}
148+
```
149+
150+
For more targeted control, specify which attributes to ignore:
151+
152+
```hcl
153+
resource "docker_container" "workspace" {
154+
lifecycle {
155+
ignore_changes = [name]
156+
}
157+
158+
count = data.coder_workspace.me.start_count
159+
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
160+
...
161+
}
162+
```
163+
164+
Learn more about `ignore_changes` in the [Terraform documentation](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle#ignore_changes).
165+
166+
### Current limitations
167+
168+
The prebuilt workspaces feature has these current limitations:
169+
170+
- **Organizations**
171+
172+
Prebuilt workspaces can only be used with the default organization.
173+
174+
[coder/internal#364](https://github.com/coder/internal/issues/364)
175+
176+
- **Autoscaling**
177+
178+
Prebuilt workspaces remain running until claimed. There's no automated mechanism to reduce instances during off-hours.
179+
180+
[coder/internal#312](https://github.com/coder/internal/issues/312)
181+
182+
### Monitoring and observability
183+
184+
#### Available metrics
185+
186+
Coder provides several metrics to monitor your prebuilt workspaces:
187+
188+
- `coderd_prebuilt_workspaces_created_total` (counter): Total number of prebuilt workspaces created to meet the desired instance count.
189+
- `coderd_prebuilt_workspaces_failed_total` (counter): Total number of prebuilt workspaces that failed to build.
190+
- `coderd_prebuilt_workspaces_claimed_total` (counter): Total number of prebuilt workspaces claimed by users.
191+
- `coderd_prebuilt_workspaces_desired` (gauge): Target number of prebuilt workspaces that should be available.
192+
- `coderd_prebuilt_workspaces_running` (gauge): Current number of prebuilt workspaces in a `running` state.
193+
- `coderd_prebuilt_workspaces_eligible` (gauge): Current number of prebuilt workspaces eligible to be claimed.
194+
195+
#### Logs
196+
197+
Search for `coderd.prebuilds:` in your logs to track the reconciliation loop's behavior.
198+
199+
These logs provide information about:
200+
201+
1. Creation and deletion attempts for prebuilt workspaces.
202+
1. Backoff events after failed builds.
203+
1. Claiming operations.

docs/manifest.json

+6
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,12 @@
437437
"description": "Use parameters to customize workspaces at build",
438438
"path": "./admin/templates/extending-templates/parameters.md"
439439
},
440+
{
441+
"title": "Prebuilt workspaces",
442+
"description": "Pre-provision a ready-to-deploy workspace with a defined set of parameters",
443+
"path": "./admin/templates/extending-templates/prebuilt-workspaces.md",
444+
"state": ["premium", "beta"]
445+
},
440446
{
441447
"title": "Icons",
442448
"description": "Customize your template with built-in icons",

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,10 @@ require (
9898
github.com/coder/flog v1.1.0
9999
github.com/coder/guts v1.3.1-0.20250428170043-ad369017e95b
100100
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0
101-
github.com/coder/quartz v0.1.2
101+
github.com/coder/quartz v0.1.3
102102
github.com/coder/retry v1.5.1
103103
github.com/coder/serpent v0.10.0
104-
github.com/coder/terraform-provider-coder/v2 v2.4.0-pre1.0.20250417100258-c86bb5c3ddcd
104+
github.com/coder/terraform-provider-coder/v2 v2.4.0
105105
github.com/coder/websocket v1.8.13
106106
github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0
107107
github.com/coreos/go-oidc/v3 v3.14.1
@@ -488,7 +488,7 @@ require (
488488

489489
require (
490490
github.com/anthropics/anthropic-sdk-go v0.2.0-beta.3
491-
github.com/coder/preview v0.0.2-0.20250506154333-6f500ca7b245
491+
github.com/coder/preview v0.0.2-0.20250509141204-fc9484dbe506
492492
github.com/fsnotify/fsnotify v1.9.0
493493
github.com/kylecarbs/aisdk-go v0.0.8
494494
github.com/mark3labs/mcp-go v0.25.0

0 commit comments

Comments
 (0)