diff --git a/cli/testdata/coder_server_--help.golden b/cli/testdata/coder_server_--help.golden
index 19857cf8ebe76..4b1fa1ca4e6c9 100644
--- a/cli/testdata/coder_server_--help.golden
+++ b/cli/testdata/coder_server_--help.golden
@@ -677,6 +677,12 @@ workspaces stopping during the day due to template scheduling.
must be *. Only one hour and minute can be specified (ranges or comma
separated values are not supported).
+WORKSPACE PREBUILDS OPTIONS:
+Configure how workspace prebuilds behave.
+
+ --workspace-prebuilds-reconciliation-interval duration, $CODER_WORKSPACE_PREBUILDS_RECONCILIATION_INTERVAL (default: 15s)
+ How often to reconcile workspace prebuilds state.
+
⚠️ DANGEROUS OPTIONS:
--dangerous-allow-path-app-sharing bool, $CODER_DANGEROUS_ALLOW_PATH_APP_SHARING
Allow workspace apps that are not served from subdomains to be shared.
diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go
index cbcfe1d72b380..522ba671a9a63 100644
--- a/coderd/apidoc/docs.go
+++ b/coderd/apidoc/docs.go
@@ -12194,15 +12194,13 @@ const docTemplate = `{
"auto-fill-parameters",
"notifications",
"workspace-usage",
- "web-push",
- "workspace-prebuilds"
+ "web-push"
],
"x-enum-comments": {
"ExperimentAutoFillParameters": "This should not be taken out of experiments until we have redesigned the feature.",
"ExperimentExample": "This isn't used for anything.",
"ExperimentNotifications": "Sends notifications via SMTP and webhooks following certain events.",
"ExperimentWebPush": "Enables web push notifications through the browser.",
- "ExperimentWorkspacePrebuilds": "Enables the new workspace prebuilds feature.",
"ExperimentWorkspaceUsage": "Enables the new workspace usage tracking."
},
"x-enum-varnames": [
@@ -12210,8 +12208,7 @@ const docTemplate = `{
"ExperimentAutoFillParameters",
"ExperimentNotifications",
"ExperimentWorkspaceUsage",
- "ExperimentWebPush",
- "ExperimentWorkspacePrebuilds"
+ "ExperimentWebPush"
]
},
"codersdk.ExternalAuth": {
diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json
index ef723652a0941..abcae550a4ec5 100644
--- a/coderd/apidoc/swagger.json
+++ b/coderd/apidoc/swagger.json
@@ -10927,15 +10927,13 @@
"auto-fill-parameters",
"notifications",
"workspace-usage",
- "web-push",
- "workspace-prebuilds"
+ "web-push"
],
"x-enum-comments": {
"ExperimentAutoFillParameters": "This should not be taken out of experiments until we have redesigned the feature.",
"ExperimentExample": "This isn't used for anything.",
"ExperimentNotifications": "Sends notifications via SMTP and webhooks following certain events.",
"ExperimentWebPush": "Enables web push notifications through the browser.",
- "ExperimentWorkspacePrebuilds": "Enables the new workspace prebuilds feature.",
"ExperimentWorkspaceUsage": "Enables the new workspace usage tracking."
},
"x-enum-varnames": [
@@ -10943,8 +10941,7 @@
"ExperimentAutoFillParameters",
"ExperimentNotifications",
"ExperimentWorkspaceUsage",
- "ExperimentWebPush",
- "ExperimentWorkspacePrebuilds"
+ "ExperimentWebPush"
]
},
"codersdk.ExternalAuth": {
diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go
index 0361bf796cb55..6d1c8c3df601c 100644
--- a/coderd/database/dbauthz/dbauthz_test.go
+++ b/coderd/database/dbauthz/dbauthz_test.go
@@ -5059,8 +5059,7 @@ func (s *MethodTestSuite) TestPrebuilds() {
}))
s.Run("GetPrebuildMetrics", s.Subtest(func(_ database.Store, check *expects) {
check.Args().
- Asserts(rbac.ResourceWorkspace.All(), policy.ActionRead).
- ErrorsWithInMemDB(dbmem.ErrUnimplemented)
+ Asserts(rbac.ResourceWorkspace.All(), policy.ActionRead)
}))
s.Run("CountInProgressPrebuilds", s.Subtest(func(_ database.Store, check *expects) {
check.Args().
diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go
index e5604d440073b..cd1067e61dbb5 100644
--- a/coderd/database/dbmem/dbmem.go
+++ b/coderd/database/dbmem/dbmem.go
@@ -4270,7 +4270,7 @@ func (q *FakeQuerier) GetParameterSchemasByJobID(_ context.Context, jobID uuid.U
}
func (*FakeQuerier) GetPrebuildMetrics(_ context.Context) ([]database.GetPrebuildMetricsRow, error) {
- return nil, ErrUnimplemented
+ return make([]database.GetPrebuildMetricsRow, 0), nil
}
func (q *FakeQuerier) GetPresetByID(ctx context.Context, presetID uuid.UUID) (database.GetPresetByIDRow, error) {
diff --git a/coderd/telemetry/telemetry.go b/coderd/telemetry/telemetry.go
index dfc27418f4862..747cf2cb47de1 100644
--- a/coderd/telemetry/telemetry.go
+++ b/coderd/telemetry/telemetry.go
@@ -687,10 +687,6 @@ func (r *remoteReporter) createSnapshot() (*Snapshot, error) {
return nil
})
eg.Go(func() error {
- if !r.options.Experiments.Enabled(codersdk.ExperimentWorkspacePrebuilds) {
- return nil
- }
-
metrics, err := r.options.Database.GetPrebuildMetrics(ctx)
if err != nil {
return xerrors.Errorf("get prebuild metrics: %w", err)
diff --git a/coderd/telemetry/telemetry_test.go b/coderd/telemetry/telemetry_test.go
index 9338e87d6d31c..ac836317b680e 100644
--- a/coderd/telemetry/telemetry_test.go
+++ b/coderd/telemetry/telemetry_test.go
@@ -408,7 +408,6 @@ func TestPrebuiltWorkspacesTelemetry(t *testing.T) {
cases := []struct {
name string
- experimentEnabled bool
storeFn func(store database.Store) database.Store
expectedSnapshotEntries int
expectedCreated int
@@ -416,8 +415,7 @@ func TestPrebuiltWorkspacesTelemetry(t *testing.T) {
expectedClaimed int
}{
{
- name: "experiment enabled",
- experimentEnabled: true,
+ name: "prebuilds enabled",
storeFn: func(store database.Store) database.Store {
return &mockDB{Store: store}
},
@@ -427,19 +425,11 @@ func TestPrebuiltWorkspacesTelemetry(t *testing.T) {
expectedClaimed: 3,
},
{
- name: "experiment enabled, prebuilds not used",
- experimentEnabled: true,
+ name: "prebuilds not used",
storeFn: func(store database.Store) database.Store {
return &emptyMockDB{Store: store}
},
},
- {
- name: "experiment disabled",
- experimentEnabled: false,
- storeFn: func(store database.Store) database.Store {
- return &mockDB{Store: store}
- },
- },
}
for _, tc := range cases {
@@ -448,11 +438,6 @@ func TestPrebuiltWorkspacesTelemetry(t *testing.T) {
deployment, snapshot := collectSnapshot(ctx, t, db, func(opts telemetry.Options) telemetry.Options {
opts.Database = tc.storeFn(db)
- if tc.experimentEnabled {
- opts.Experiments = codersdk.Experiments{
- codersdk.ExperimentWorkspacePrebuilds,
- }
- }
return opts
})
diff --git a/codersdk/deployment.go b/codersdk/deployment.go
index ef0b4eaa07821..544e98f6f2a72 100644
--- a/codersdk/deployment.go
+++ b/codersdk/deployment.go
@@ -3070,7 +3070,6 @@ Write out the current server config as YAML to stdout.`,
Group: &deploymentGroupPrebuilds,
YAML: "reconciliation_interval",
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
- Hidden: ExperimentsSafe.Enabled(ExperimentWorkspacePrebuilds), // Hide setting while this feature is experimental.
},
{
Name: "Reconciliation Backoff Interval",
@@ -3342,7 +3341,6 @@ const (
ExperimentNotifications Experiment = "notifications" // Sends notifications via SMTP and webhooks following certain events.
ExperimentWorkspaceUsage Experiment = "workspace-usage" // Enables the new workspace usage tracking.
ExperimentWebPush Experiment = "web-push" // Enables web push notifications through the browser.
- ExperimentWorkspacePrebuilds Experiment = "workspace-prebuilds" // Enables the new workspace prebuilds feature.
)
// ExperimentsKnown should include all experiments defined above.
@@ -3352,16 +3350,13 @@ var ExperimentsKnown = Experiments{
ExperimentNotifications,
ExperimentWorkspaceUsage,
ExperimentWebPush,
- ExperimentWorkspacePrebuilds,
}
// ExperimentsSafe should include all experiments that are safe for
// users to opt-in to via --experimental='*'.
// Experiments that are not ready for consumption by all users should
// not be included here and will be essentially hidden.
-var ExperimentsSafe = Experiments{
- ExperimentWorkspacePrebuilds,
-}
+var ExperimentsSafe = Experiments{}
// Experiments is a list of experiments.
// Multiple experiments may be enabled at the same time.
diff --git a/docs/admin/templates/extending-templates/prebuilt-workspaces.md b/docs/admin/templates/extending-templates/prebuilt-workspaces.md
index 08a404e040159..9d33425019b50 100644
--- a/docs/admin/templates/extending-templates/prebuilt-workspaces.md
+++ b/docs/admin/templates/extending-templates/prebuilt-workspaces.md
@@ -27,7 +27,6 @@ Prebuilt workspaces are tightly integrated with [workspace presets](./parameters
- [**Premium license**](../../licensing/index.md)
- **Compatible Terraform provider**: Use `coder/coder` Terraform provider `>= 2.4.1`.
-- **Feature flag**: Enable the `workspace-prebuilds` [experiment](../../../reference/cli/server.md#--experiments).
## Enable prebuilt workspaces for template presets
diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md
index e19c9d15da413..79c6f817bc776 100644
--- a/docs/reference/api/schemas.md
+++ b/docs/reference/api/schemas.md
@@ -2996,7 +2996,6 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o
| `notifications` |
| `workspace-usage` |
| `web-push` |
-| `workspace-prebuilds` |
## codersdk.ExternalAuth
diff --git a/docs/reference/cli/server.md b/docs/reference/cli/server.md
index 644065d35076f..f52b3666a866e 100644
--- a/docs/reference/cli/server.md
+++ b/docs/reference/cli/server.md
@@ -1615,6 +1615,17 @@ Enable Coder Inbox.
The upper limit of attempts to send a notification.
+### --workspace-prebuilds-reconciliation-interval
+
+| | |
+|-------------|-----------------------------------------------------------------|
+| Type | duration
|
+| Environment | $CODER_WORKSPACE_PREBUILDS_RECONCILIATION_INTERVAL
|
+| YAML | workspace_prebuilds.reconciliation_interval
|
+| Default | 15s
|
+
+How often to reconcile workspace prebuilds state.
+
### --hide-ai-tasks
| | |
diff --git a/enterprise/cli/testdata/coder_server_--help.golden b/enterprise/cli/testdata/coder_server_--help.golden
index 3e3868c5ae432..d7c26bc537693 100644
--- a/enterprise/cli/testdata/coder_server_--help.golden
+++ b/enterprise/cli/testdata/coder_server_--help.golden
@@ -678,6 +678,12 @@ workspaces stopping during the day due to template scheduling.
must be *. Only one hour and minute can be specified (ranges or comma
separated values are not supported).
+WORKSPACE PREBUILDS OPTIONS:
+Configure how workspace prebuilds behave.
+
+ --workspace-prebuilds-reconciliation-interval duration, $CODER_WORKSPACE_PREBUILDS_RECONCILIATION_INTERVAL (default: 15s)
+ How often to reconcile workspace prebuilds state.
+
⚠️ DANGEROUS OPTIONS:
--dangerous-allow-path-app-sharing bool, $CODER_DANGEROUS_ALLOW_PATH_APP_SHARING
Allow workspace apps that are not served from subdomains to be shared.
diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go
index 9b168c8e3f366..601700403f326 100644
--- a/enterprise/coderd/coderd.go
+++ b/enterprise/coderd/coderd.go
@@ -1150,16 +1150,9 @@ func (api *API) Authorize(r *http.Request, action policy.Action, object rbac.Obj
// nolint:revive // featureEnabled is a legit control flag.
func (api *API) setupPrebuilds(featureEnabled bool) (agplprebuilds.ReconciliationOrchestrator, agplprebuilds.Claimer) {
- experimentEnabled := api.AGPL.Experiments.Enabled(codersdk.ExperimentWorkspacePrebuilds)
- if !experimentEnabled || !featureEnabled {
- levelFn := api.Logger.Debug
- // If the experiment is enabled but the license does not entitle the feature, operators should be warned.
- if !featureEnabled {
- levelFn = api.Logger.Warn
- }
-
- levelFn(context.Background(), "prebuilds not enabled; ensure you have a premium license and the 'workspace-prebuilds' experiment set",
- slog.F("experiment_enabled", experimentEnabled), slog.F("feature_enabled", featureEnabled))
+ if !featureEnabled {
+ api.Logger.Warn(context.Background(), "prebuilds not enabled; ensure you have a premium license",
+ slog.F("feature_enabled", featureEnabled))
return agplprebuilds.DefaultReconciler, agplprebuilds.DefaultClaimer
}
diff --git a/enterprise/coderd/coderd_test.go b/enterprise/coderd/coderd_test.go
index 1c8c863db040b..89a61c657e21a 100644
--- a/enterprise/coderd/coderd_test.go
+++ b/enterprise/coderd/coderd_test.go
@@ -260,34 +260,19 @@ func TestEntitlements_Prebuilds(t *testing.T) {
t.Parallel()
cases := []struct {
- name string
- experimentEnabled bool
- featureEnabled bool
- expectedEnabled bool
+ name string
+ featureEnabled bool
+ expectedEnabled bool
}{
{
- name: "Fully enabled",
- featureEnabled: true,
- experimentEnabled: true,
- expectedEnabled: true,
+ name: "Feature enabled",
+ featureEnabled: true,
+ expectedEnabled: true,
},
{
- name: "Feature disabled",
- featureEnabled: false,
- experimentEnabled: true,
- expectedEnabled: false,
- },
- {
- name: "Experiment disabled",
- featureEnabled: true,
- experimentEnabled: false,
- expectedEnabled: false,
- },
- {
- name: "Fully disabled",
- featureEnabled: false,
- experimentEnabled: false,
- expectedEnabled: false,
+ name: "Feature disabled",
+ featureEnabled: false,
+ expectedEnabled: false,
},
}
@@ -302,11 +287,7 @@ func TestEntitlements_Prebuilds(t *testing.T) {
_, _, api, _ := coderdenttest.NewWithAPI(t, &coderdenttest.Options{
Options: &coderdtest.Options{
- DeploymentValues: coderdtest.DeploymentValues(t, func(values *codersdk.DeploymentValues) {
- if tc.experimentEnabled {
- values.Experiments = serpent.StringArray{string(codersdk.ExperimentWorkspacePrebuilds)}
- }
- }),
+ DeploymentValues: coderdtest.DeploymentValues(t),
},
EntitlementsUpdateInterval: time.Second,
diff --git a/enterprise/coderd/workspaceagents_test.go b/enterprise/coderd/workspaceagents_test.go
index 1eea9ecda9ca8..f4f0670cd150e 100644
--- a/enterprise/coderd/workspaceagents_test.go
+++ b/enterprise/coderd/workspaceagents_test.go
@@ -112,7 +112,6 @@ func TestReinitializeAgent(t *testing.T) {
Pubsub: ps,
DeploymentValues: coderdtest.DeploymentValues(t, func(dv *codersdk.DeploymentValues) {
dv.Prebuilds.ReconciliationInterval = serpent.Duration(time.Second)
- dv.Experiments.Append(string(codersdk.ExperimentWorkspacePrebuilds))
}),
},
LicenseOptions: &coderdenttest.LicenseOptions{
diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go
index 228b11f485a96..3bed052702637 100644
--- a/enterprise/coderd/workspaces_test.go
+++ b/enterprise/coderd/workspaces_test.go
@@ -531,10 +531,7 @@ func TestCreateUserWorkspace(t *testing.T) {
client, db, user := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
Options: &coderdtest.Options{
- DeploymentValues: coderdtest.DeploymentValues(t, func(dv *codersdk.DeploymentValues) {
- err := dv.Experiments.Append(string(codersdk.ExperimentWorkspacePrebuilds))
- require.NoError(t, err)
- }),
+ DeploymentValues: coderdtest.DeploymentValues(t),
},
LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index b2117cf15c987..0e6a481406d8b 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -795,7 +795,6 @@ export type Experiment =
| "example"
| "notifications"
| "web-push"
- | "workspace-prebuilds"
| "workspace-usage";
export const Experiments: Experiment[] = [
@@ -803,7 +802,6 @@ export const Experiments: Experiment[] = [
"example",
"notifications",
"web-push",
- "workspace-prebuilds",
"workspace-usage",
];