diff --git a/cli/server.go b/cli/server.go index b12f5e0189..010e96d2fc 100644 --- a/cli/server.go +++ b/cli/server.go @@ -1476,6 +1476,7 @@ func newProvisionerDaemon( Listener: terraformServer, Logger: provisionerLogger, WorkDirectory: workDir, + Experiments: coderAPI.Experiments, }, CachePath: tfDir, Tracer: tracer, diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index a67b2cb7c7..67dc827927 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -14322,7 +14322,8 @@ const docTemplate = `{ "web-push", "oauth2", "mcp-server-http", - "workspace-sharing" + "workspace-sharing", + "terraform-directory-reuse" ], "x-enum-comments": { "ExperimentAutoFillParameters": "This should not be taken out of experiments until we have redesigned the feature.", @@ -14330,6 +14331,7 @@ const docTemplate = `{ "ExperimentMCPServerHTTP": "Enables the MCP HTTP server functionality.", "ExperimentNotifications": "Sends notifications via SMTP and webhooks following certain events.", "ExperimentOAuth2": "Enables OAuth2 provider functionality.", + "ExperimentTerraformWorkspace": "Enables reuse of existing terraform directory for builds", "ExperimentWebPush": "Enables web push notifications through the browser.", "ExperimentWorkspaceSharing": "Enables updating workspace ACLs for sharing with users and groups.", "ExperimentWorkspaceUsage": "Enables the new workspace usage tracking." @@ -14342,7 +14344,8 @@ const docTemplate = `{ "ExperimentWebPush", "ExperimentOAuth2", "ExperimentMCPServerHTTP", - "ExperimentWorkspaceSharing" + "ExperimentWorkspaceSharing", + "ExperimentTerraformWorkspace" ] }, "codersdk.ExternalAPIKeyScopes": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 4e1bd64ebe..1577e55b86 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -12929,7 +12929,8 @@ "web-push", "oauth2", "mcp-server-http", - "workspace-sharing" + "workspace-sharing", + "terraform-directory-reuse" ], "x-enum-comments": { "ExperimentAutoFillParameters": "This should not be taken out of experiments until we have redesigned the feature.", @@ -12937,6 +12938,7 @@ "ExperimentMCPServerHTTP": "Enables the MCP HTTP server functionality.", "ExperimentNotifications": "Sends notifications via SMTP and webhooks following certain events.", "ExperimentOAuth2": "Enables OAuth2 provider functionality.", + "ExperimentTerraformWorkspace": "Enables reuse of existing terraform directory for builds", "ExperimentWebPush": "Enables web push notifications through the browser.", "ExperimentWorkspaceSharing": "Enables updating workspace ACLs for sharing with users and groups.", "ExperimentWorkspaceUsage": "Enables the new workspace usage tracking." @@ -12949,7 +12951,8 @@ "ExperimentWebPush", "ExperimentOAuth2", "ExperimentMCPServerHTTP", - "ExperimentWorkspaceSharing" + "ExperimentWorkspaceSharing", + "ExperimentTerraformWorkspace" ] }, "codersdk.ExternalAPIKeyScopes": { diff --git a/coderd/coderd.go b/coderd/coderd.go index fd361c1e0e..a9683ace20 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1999,6 +1999,7 @@ func (api *API) CreateInMemoryTaggedProvisionerDaemon(dialCtx context.Context, n api.NotificationsEnqueuer, &api.PrebuildsReconciler, api.ProvisionerdServerMetrics, + api.Experiments, ) if err != nil { return nil, err diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index dec8ab6d38..f5ffadb29f 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -121,6 +121,7 @@ type server struct { NotificationsEnqueuer notifications.Enqueuer PrebuildsOrchestrator *atomic.Pointer[prebuilds.ReconciliationOrchestrator] UsageInserter *atomic.Pointer[usage.Inserter] + Experiments codersdk.Experiments OIDCConfig promoauth.OAuth2Config @@ -182,6 +183,7 @@ func NewServer( enqueuer notifications.Enqueuer, prebuildsOrchestrator *atomic.Pointer[prebuilds.ReconciliationOrchestrator], metrics *Metrics, + experiments codersdk.Experiments, ) (proto.DRPCProvisionerDaemonServer, error) { // Fail-fast if pointers are nil if lifecycleCtx == nil { @@ -253,6 +255,7 @@ func NewServer( PrebuildsOrchestrator: prebuildsOrchestrator, UsageInserter: usageInserter, metrics: metrics, + Experiments: experiments, } if s.heartbeatFn == nil { diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index d4597f6546..3d31251fcd 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -26,6 +26,7 @@ import ( "storj.io/drpc" "cdr.dev/slog/sloggers/slogtest" + "github.com/coder/coder/v2/coderd" "github.com/coder/coder/v2/coderd/util/ptr" "github.com/coder/quartz" "github.com/coder/serpent" @@ -4162,7 +4163,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi defOrg, err := db.GetDefaultOrganization(context.Background()) require.NoError(t, err, "default org not found") - deploymentValues := &codersdk.DeploymentValues{} + deploymentValues := coderdtest.DeploymentValues(t) var externalAuthConfigs []*externalauth.Config tss := testTemplateScheduleStore() uqhss := testUserQuietHoursScheduleStore() @@ -4285,6 +4286,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi notifEnq, &op, provisionerdserver.NewMetrics(logger), + coderd.ReadExperiments(logger, deploymentValues.Experiments), ) require.NoError(t, err) return srv, db, ps, daemon diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 4d79058b68..073ab7faed 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -3646,6 +3646,8 @@ const ( ExperimentOAuth2 Experiment = "oauth2" // Enables OAuth2 provider functionality. ExperimentMCPServerHTTP Experiment = "mcp-server-http" // Enables the MCP HTTP server functionality. ExperimentWorkspaceSharing Experiment = "workspace-sharing" // Enables updating workspace ACLs for sharing with users and groups. + // ExperimentTerraformWorkspace uses the "Terraform Workspaces" feature, not to be confused with Coder Workspaces. + ExperimentTerraformWorkspace Experiment = "terraform-directory-reuse" // Enables reuse of existing terraform directory for builds ) func (e Experiment) DisplayName() string { @@ -3666,6 +3668,8 @@ func (e Experiment) DisplayName() string { return "MCP HTTP Server Functionality" case ExperimentWorkspaceSharing: return "Workspace Sharing" + case ExperimentTerraformWorkspace: + return "Terraform Directory Reuse" default: // Split on hyphen and convert to title case // e.g. "web-push" -> "Web Push", "mcp-server-http" -> "Mcp Server Http" diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index f5ca96c98b..e466abaa6f 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -4057,16 +4057,17 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o #### Enumerated Values -| Value | -|------------------------| -| `example` | -| `auto-fill-parameters` | -| `notifications` | -| `workspace-usage` | -| `web-push` | -| `oauth2` | -| `mcp-server-http` | -| `workspace-sharing` | +| Value | +|-----------------------------| +| `example` | +| `auto-fill-parameters` | +| `notifications` | +| `workspace-usage` | +| `web-push` | +| `oauth2` | +| `mcp-server-http` | +| `workspace-sharing` | +| `terraform-directory-reuse` | ## codersdk.ExternalAPIKeyScopes diff --git a/docs/reference/cli/provisioner_start.md b/docs/reference/cli/provisioner_start.md index 2a3c88ff93..f278bac310 100644 --- a/docs/reference/cli/provisioner_start.md +++ b/docs/reference/cli/provisioner_start.md @@ -144,6 +144,16 @@ Serve prometheus metrics on the address defined by prometheus address. The bind address to serve prometheus metrics. +### --experiments + +| | | +|-------------|---------------------------------| +| Type | string-array | +| Environment | $CODER_EXPERIMENTS | +| YAML | experiments | + +Enable one or more experiments. These are not ready for production. Separate multiple experiments with commas, or enter '*' to opt-in to all available experiments. + ### -O, --org | | | diff --git a/enterprise/cli/provisionerdaemonstart.go b/enterprise/cli/provisionerdaemonstart.go index 1869007a85..4c0ed003a1 100644 --- a/enterprise/cli/provisionerdaemonstart.go +++ b/enterprise/cli/provisionerdaemonstart.go @@ -23,6 +23,7 @@ import ( "github.com/coder/coder/v2/cli/clilog" "github.com/coder/coder/v2/cli/cliui" "github.com/coder/coder/v2/cli/cliutil" + "github.com/coder/coder/v2/coderd" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/drpcsdk" @@ -48,6 +49,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { preSharedKey string provisionerKey string verbose bool + experiments []string prometheusEnable bool prometheusAddress string @@ -186,6 +188,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { Listener: terraformServer, Logger: logger.Named("terraform"), WorkDirectory: tempDir, + Experiments: coderd.ReadExperiments(logger, experiments), }, CachePath: cacheDir, }) @@ -378,6 +381,14 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { Value: serpent.StringOf(&prometheusAddress), Default: "127.0.0.1:2112", }, + { + Name: "Experiments", + Description: "Enable one or more experiments. These are not ready for production. Separate multiple experiments with commas, or enter '*' to opt-in to all available experiments.", + Flag: "experiments", + Env: "CODER_EXPERIMENTS", + Value: serpent.StringArrayOf(&experiments), + YAML: "experiments", + }, } orgContext.AttachOptions(cmd) diff --git a/enterprise/cli/testdata/coder_provisioner_start_--help.golden b/enterprise/cli/testdata/coder_provisioner_start_--help.golden index 439a2d68ba..e3d4c69a8c 100644 --- a/enterprise/cli/testdata/coder_provisioner_start_--help.golden +++ b/enterprise/cli/testdata/coder_provisioner_start_--help.golden @@ -6,6 +6,11 @@ USAGE: Run a provisioner daemon OPTIONS: + --experiments string-array, $CODER_EXPERIMENTS + Enable one or more experiments. These are not ready for production. + Separate multiple experiments with commas, or enter '*' to opt-in to + all available experiments. + -O, --org string, $CODER_ORGANIZATION Select which organization (uuid or name) to use. diff --git a/enterprise/coderd/coderdenttest/coderdenttest.go b/enterprise/coderd/coderdenttest/coderdenttest.go index a31d1d495b..29758c3dbf 100644 --- a/enterprise/coderd/coderdenttest/coderdenttest.go +++ b/enterprise/coderd/coderdenttest/coderdenttest.go @@ -414,6 +414,7 @@ func newExternalProvisionerDaemon(t testing.TB, client *codersdk.Client, org uui ServeOptions: &provisionersdk.ServeOptions{ Listener: provisionerSrv, WorkDirectory: t.TempDir(), + Experiments: codersdk.Experiments{}, }, })) }() diff --git a/enterprise/coderd/provisionerdaemons.go b/enterprise/coderd/provisionerdaemons.go index be03af2929..0f6db2508a 100644 --- a/enterprise/coderd/provisionerdaemons.go +++ b/enterprise/coderd/provisionerdaemons.go @@ -362,6 +362,7 @@ func (api *API) provisionerDaemonServe(rw http.ResponseWriter, r *http.Request) api.NotificationsEnqueuer, &api.AGPL.PrebuildsReconciler, api.ProvisionerdServerMetrics, + api.AGPL.Experiments, ) if err != nil { if !xerrors.Is(err, context.Canceled) { diff --git a/provisionersdk/serve.go b/provisionersdk/serve.go index c652cfa949..3bac226e58 100644 --- a/provisionersdk/serve.go +++ b/provisionersdk/serve.go @@ -15,6 +15,7 @@ import ( "storj.io/drpc/drpcserver" "cdr.dev/slog" + "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/drpcsdk" "github.com/coder/coder/v2/coderd/tracing" @@ -30,6 +31,7 @@ type ServeOptions struct { Logger slog.Logger WorkDirectory string ExternalProvisioner bool + Experiments codersdk.Experiments } type Server interface { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 76a83e00c5..ea65957316 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1895,6 +1895,7 @@ export type Experiment = | "mcp-server-http" | "notifications" | "oauth2" + | "terraform-directory-reuse" | "web-push" | "workspace-sharing" | "workspace-usage"; @@ -1905,6 +1906,7 @@ export const Experiments: Experiment[] = [ "mcp-server-http", "notifications", "oauth2", + "terraform-directory-reuse", "web-push", "workspace-sharing", "workspace-usage",