diff --git a/cli/autoupdate_test.go b/cli/autoupdate_test.go index 2022dc7fe2366..51001d5109755 100644 --- a/cli/autoupdate_test.go +++ b/cli/autoupdate_test.go @@ -24,7 +24,7 @@ func TestAutoUpdate(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) require.Equal(t, codersdk.AutomaticUpdatesNever, workspace.AutomaticUpdates) diff --git a/cli/clitest/golden.go b/cli/clitest/golden.go index 635ced97d4b50..db0bbeb43874e 100644 --- a/cli/clitest/golden.go +++ b/cli/clitest/golden.go @@ -195,7 +195,7 @@ func prepareTestData(t *testing.T) (*codersdk.Client, map[string]string) { template := coderdtest.CreateTemplate(t, rootClient, firstUser.OrganizationID, version.ID, func(req *codersdk.CreateTemplateRequest) { req.Name = "test-template" }) - workspace := coderdtest.CreateWorkspace(t, rootClient, firstUser.OrganizationID, template.ID, func(req *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, rootClient, template.ID, func(req *codersdk.CreateWorkspaceRequest) { req.Name = "test-workspace" }) workspaceBuild := coderdtest.AwaitWorkspaceBuildJobCompleted(t, rootClient, workspace.LatestBuild.ID) diff --git a/cli/delete_test.go b/cli/delete_test.go index 0a08ffe55f161..e5baee70fe5d9 100644 --- a/cli/delete_test.go +++ b/cli/delete_test.go @@ -27,7 +27,7 @@ func TestDelete(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) inv, root := clitest.New(t, "delete", workspace.Name, "-y") clitest.SetupConfig(t, member, root) @@ -52,7 +52,7 @@ func TestDelete(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) inv, root := clitest.New(t, "delete", workspace.Name, "-y", "--orphan") @@ -86,8 +86,7 @@ func TestDelete(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - - workspace := coderdtest.CreateWorkspace(t, deleteMeClient, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, deleteMeClient, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, deleteMeClient, workspace.LatestBuild.ID) // The API checks if the user has any workspaces, so we cannot delete a user @@ -128,7 +127,7 @@ func TestDelete(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, adminClient, orgID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, adminClient, version.ID) template := coderdtest.CreateTemplate(t, adminClient, orgID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, orgID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) inv, root := clitest.New(t, "delete", user.Username+"/"+workspace.Name, "-y") diff --git a/cli/rename_test.go b/cli/rename_test.go index b31a45671e47e..31d14e5e08184 100644 --- a/cli/rename_test.go +++ b/cli/rename_test.go @@ -21,7 +21,7 @@ func TestRename(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) diff --git a/cli/restart_test.go b/cli/restart_test.go index 56b7230797843..d81169b8c4aba 100644 --- a/cli/restart_test.go +++ b/cli/restart_test.go @@ -38,7 +38,7 @@ func TestRestart(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx := testutil.Context(t, testutil.WaitLong) @@ -69,7 +69,7 @@ func TestRestart(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) inv, root := clitest.New(t, "restart", workspace.Name, "--build-options") @@ -123,7 +123,7 @@ func TestRestart(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) inv, root := clitest.New(t, "restart", workspace.Name, @@ -202,7 +202,7 @@ func TestRestartWithParameters(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, member, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.RichParameterValues = []codersdk.WorkspaceBuildParameter{ { Name: immutableParameterName, @@ -250,7 +250,7 @@ func TestRestartWithParameters(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, mutableParamsResponse) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, member, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.RichParameterValues = []codersdk.WorkspaceBuildParameter{ { Name: mutableParameterName, diff --git a/cli/show_test.go b/cli/show_test.go index eff2789e75a02..7191898f8c0ec 100644 --- a/cli/show_test.go +++ b/cli/show_test.go @@ -20,7 +20,7 @@ func TestShow(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, completeWithAgent()) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) args := []string{ diff --git a/cli/ssh_test.go b/cli/ssh_test.go index ae93c4b0cea05..d000e090a44e4 100644 --- a/cli/ssh_test.go +++ b/cli/ssh_test.go @@ -108,7 +108,7 @@ func TestSSH(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Stop the workspace workspaceBuild := coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStop) @@ -166,7 +166,7 @@ func TestSSH(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, ownerClient, version.ID) template := coderdtest.CreateTemplate(t, ownerClient, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, owner.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutomaticUpdates = codersdk.AutomaticUpdatesAlways }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) @@ -373,7 +373,7 @@ func TestSSH(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Stop the workspace workspaceBuild := coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStop) diff --git a/cli/start_test.go b/cli/start_test.go index 40b57bacaf729..404052745f00b 100644 --- a/cli/start_test.go +++ b/cli/start_test.go @@ -109,7 +109,7 @@ func TestStart(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Stop the workspace workspaceBuild := coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStop) @@ -163,7 +163,7 @@ func TestStart(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, echoResponses) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, member, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Stop the workspace workspaceBuild := coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStop) @@ -211,7 +211,7 @@ func TestStartWithParameters(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, immutableParamsResponse) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, member, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.RichParameterValues = []codersdk.WorkspaceBuildParameter{ { Name: immutableParameterName, @@ -263,7 +263,7 @@ func TestStartWithParameters(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, mutableParamsResponse) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, member, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.RichParameterValues = []codersdk.WorkspaceBuildParameter{ { Name: mutableParameterName, @@ -349,7 +349,7 @@ func TestStartAutoUpdate(t *testing.T) { version1 := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version1.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version1.ID) - workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, member, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutomaticUpdates = codersdk.AutomaticUpdatesAlways }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) diff --git a/cli/state_test.go b/cli/state_test.go index 1d746e8989a63..08f2c96d14f7b 100644 --- a/cli/state_test.go +++ b/cli/state_test.go @@ -100,7 +100,7 @@ func TestStatePush(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, templateAdmin, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, templateAdmin, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) stateFile, err := os.CreateTemp(t.TempDir(), "") require.NoError(t, err) @@ -126,7 +126,7 @@ func TestStatePush(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, templateAdmin, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, templateAdmin, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) inv, root := clitest.New(t, "state", "push", "--build", strconv.Itoa(int(workspace.LatestBuild.BuildNumber)), workspace.Name, "-") clitest.SetupConfig(t, templateAdmin, root) @@ -146,7 +146,7 @@ func TestStatePush(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, templateAdmin, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, templateAdmin, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) inv, root := clitest.New(t, "state", "push", "--build", strconv.Itoa(int(workspace.LatestBuild.BuildNumber)), diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 20c17b8d27762..90b0e7345862b 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -63,7 +63,7 @@ func TestWorkspaceActivityBump(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace = coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.TTLMillis = &ttlMillis }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 487aac8f7fb76..309decd0a324c 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -2593,6 +2593,7 @@ const docTemplate = `{ ], "summary": "Create user workspace by organization", "operationId": "create-user-workspace-by-organization", + "deprecated": true, "parameters": [ { "type": "string", @@ -5845,6 +5846,53 @@ const docTemplate = `{ } } }, + "/users/{user}/workspaces": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "description": "Create a new workspace using a template. The request must\nspecify either the Template ID or the Template Version ID,\nnot both. If the Template ID is specified, the active version\nof the template will be used.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Workspaces" + ], + "summary": "Create user workspace", + "operationId": "create-user-workspace", + "parameters": [ + { + "type": "string", + "description": "Username, UUID, or me", + "name": "user", + "in": "path", + "required": true + }, + { + "description": "Create workspace request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.CreateWorkspaceRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.Workspace" + } + } + } + } + }, "/workspace-quota/{user}": { "get": { "security": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index be72fcb8d03ac..43ab2e09f8165 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -2267,6 +2267,7 @@ "tags": ["Workspaces"], "summary": "Create user workspace by organization", "operationId": "create-user-workspace-by-organization", + "deprecated": true, "parameters": [ { "type": "string", @@ -5163,6 +5164,47 @@ } } }, + "/users/{user}/workspaces": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "description": "Create a new workspace using a template. The request must\nspecify either the Template ID or the Template Version ID,\nnot both. If the Template ID is specified, the active version\nof the template will be used.", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["Workspaces"], + "summary": "Create user workspace", + "operationId": "create-user-workspace", + "parameters": [ + { + "type": "string", + "description": "Username, UUID, or me", + "name": "user", + "in": "path", + "required": true + }, + { + "description": "Create workspace request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.CreateWorkspaceRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.Workspace" + } + } + } + } + }, "/workspace-quota/{user}": { "get": { "security": [ diff --git a/coderd/audit/request.go b/coderd/audit/request.go index eecb0b81d4d8f..6c862c6e11103 100644 --- a/coderd/audit/request.go +++ b/coderd/audit/request.go @@ -51,6 +51,12 @@ type Request[T Auditable] struct { Action database.AuditAction } +// UpdateOrganizationID can be used if the organization ID is not known +// at the initiation of an audit log request. +func (r *Request[T]) UpdateOrganizationID(id uuid.UUID) { + r.params.OrganizationID = id +} + type BackgroundAuditParams[T Auditable] struct { Audit Auditor Log slog.Logger diff --git a/coderd/audit_test.go b/coderd/audit_test.go index 6c21a1363cbcb..80b8ff911db6b 100644 --- a/coderd/audit_test.go +++ b/coderd/audit_test.go @@ -107,7 +107,7 @@ func TestAuditLogs(t *testing.T) { ) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) buildResourceInfo := audit.AdditionalFields{ @@ -236,7 +236,7 @@ func TestAuditLogsFilter(t *testing.T) { ) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) // Create two logs with "Create" err := client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{ diff --git a/coderd/autobuild/lifecycle_executor_test.go b/coderd/autobuild/lifecycle_executor_test.go index f2fb37c8b471c..d77cfa0d1941a 100644 --- a/coderd/autobuild/lifecycle_executor_test.go +++ b/coderd/autobuild/lifecycle_executor_test.go @@ -306,7 +306,7 @@ func TestExecutorAutostartUserSuspended(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, admin.OrganizationID, version.ID) userClient, user := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID) - workspace := coderdtest.CreateWorkspace(t, userClient, admin.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, userClient, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = ptr.Ref(sched.String()) }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, workspace.LatestBuild.ID) @@ -601,7 +601,7 @@ func TestExecuteAutostopSuspendedUser(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, admin.OrganizationID, version.ID) userClient, user := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID) - workspace := coderdtest.CreateWorkspace(t, userClient, admin.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, userClient, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, workspace.LatestBuild.ID) // Given: workspace is running, and the user is suspended. @@ -946,7 +946,7 @@ func TestExecutorRequireActiveVersion(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, ownerClient, inactiveVersion.ID) memberClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) - ws := coderdtest.CreateWorkspace(t, memberClient, owner.OrganizationID, uuid.Nil, func(cwr *codersdk.CreateWorkspaceRequest) { + ws := coderdtest.CreateWorkspace(t, memberClient, uuid.Nil, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.TemplateVersionID = inactiveVersion.ID cwr.AutostartSchedule = ptr.Ref(sched.String()) }) @@ -1003,7 +1003,7 @@ func TestExecutorFailedWorkspace(t *testing.T) { ctr.FailureTTLMillis = ptr.Ref[int64](failureTTL.Milliseconds()) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusFailed, build.Status) ticker <- build.Job.CompletedAt.Add(failureTTL * 2) @@ -1053,7 +1053,7 @@ func TestExecutorInactiveWorkspace(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantMillis = ptr.Ref[int64](inactiveTTL.Milliseconds()) }) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) ticker <- ws.LastUsedAt.Add(inactiveTTL * 2) @@ -1099,7 +1099,7 @@ func TestNotifications(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, admin.OrganizationID, version.ID) userClient, _ := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID) - workspace := coderdtest.CreateWorkspace(t, userClient, admin.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, userClient, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, workspace.LatestBuild.ID) // Stop workspace @@ -1131,7 +1131,7 @@ func mustProvisionWorkspace(t *testing.T, client *codersdk.Client, mut ...func(* version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, mut...) + ws := coderdtest.CreateWorkspace(t, client, template.ID, mut...) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) return coderdtest.MustWorkspace(t, client, ws.ID) } @@ -1154,7 +1154,7 @@ func mustProvisionWorkspaceWithParameters(t *testing.T, client *codersdk.Client, }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, mut...) + ws := coderdtest.CreateWorkspace(t, client, template.ID, mut...) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) return coderdtest.MustWorkspace(t, client, ws.ID) } diff --git a/coderd/coderd.go b/coderd/coderd.go index a62cdae08cc49..6f8a59ad6efc6 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1043,6 +1043,7 @@ func New(options *Options) *API { r.Get("/", api.organizationsByUser) r.Get("/{organizationname}", api.organizationByUserAndName) }) + r.Post("/workspaces", api.postUserWorkspaces) r.Route("/workspace/{workspacename}", func(r chi.Router) { r.Get("/", api.workspaceByOwnerAndName) r.Get("/builds/{buildnumber}", api.workspaceBuildByBuildNumber) diff --git a/coderd/coderd_test.go b/coderd/coderd_test.go index eb03e7ebcf9fb..ffbeec4591f4e 100644 --- a/coderd/coderd_test.go +++ b/coderd/coderd_test.go @@ -205,7 +205,7 @@ func TestDERPForceWebSockets(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) _ = agenttest.New(t, client.URL, authToken) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 883742aa5f67f..9a1640e620d31 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -1064,7 +1064,7 @@ func (w WorkspaceAgentWaiter) Wait() []codersdk.WorkspaceResource { // CreateWorkspace creates a workspace for the user and template provided. // A random name is generated for it. // To customize the defaults, pass a mutator func. -func CreateWorkspace(t testing.TB, client *codersdk.Client, organization uuid.UUID, templateID uuid.UUID, mutators ...func(*codersdk.CreateWorkspaceRequest)) codersdk.Workspace { +func CreateWorkspace(t testing.TB, client *codersdk.Client, templateID uuid.UUID, mutators ...func(*codersdk.CreateWorkspaceRequest)) codersdk.Workspace { t.Helper() req := codersdk.CreateWorkspaceRequest{ TemplateID: templateID, @@ -1076,7 +1076,7 @@ func CreateWorkspace(t testing.TB, client *codersdk.Client, organization uuid.UU for _, mutator := range mutators { mutator(&req) } - workspace, err := client.CreateWorkspace(context.Background(), organization, codersdk.Me, req) + workspace, err := client.CreateUserWorkspace(context.Background(), codersdk.Me, req) require.NoError(t, err) return workspace } diff --git a/coderd/coderdtest/coderdtest_test.go b/coderd/coderdtest/coderdtest_test.go index 455a03dc119b7..d4dfae6529e8b 100644 --- a/coderd/coderdtest/coderdtest_test.go +++ b/coderd/coderdtest/coderdtest_test.go @@ -21,7 +21,7 @@ func TestNew(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID) _, _ = coderdtest.NewGoogleInstanceIdentity(t, "example", false) diff --git a/coderd/coderdtest/swaggerparser.go b/coderd/coderdtest/swaggerparser.go index 8ba4ddb507528..1b5317e05ff4c 100644 --- a/coderd/coderdtest/swaggerparser.go +++ b/coderd/coderdtest/swaggerparser.go @@ -89,9 +89,9 @@ func parseSwaggerComment(commentGroup *ast.CommentGroup) SwaggerComment { failures: []response{}, } for _, line := range commentGroup.List { - // @ [args...] + // "// @ [args...]" -> []string{"//", "@", "args..."} splitN := strings.SplitN(strings.TrimSpace(line.Text), " ", 3) - if len(splitN) < 2 { + if len(splitN) < 3 { continue // comment prefix without any content } diff --git a/coderd/externalauth_test.go b/coderd/externalauth_test.go index 916a88460d53c..a62e7eab745a0 100644 --- a/coderd/externalauth_test.go +++ b/coderd/externalauth_test.go @@ -429,7 +429,7 @@ func TestExternalAuthCallback(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) agentClient := agentsdk.New(client.URL) @@ -461,7 +461,7 @@ func TestExternalAuthCallback(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) agentClient := agentsdk.New(client.URL) @@ -533,7 +533,7 @@ func TestExternalAuthCallback(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) agentClient := agentsdk.New(client.URL) @@ -595,7 +595,7 @@ func TestExternalAuthCallback(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) agentClient := agentsdk.New(client.URL) @@ -642,7 +642,7 @@ func TestExternalAuthCallback(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) agentClient := agentsdk.New(client.URL) diff --git a/coderd/gitsshkey_test.go b/coderd/gitsshkey_test.go index 6637a20ef7a92..22d23176aa1c8 100644 --- a/coderd/gitsshkey_test.go +++ b/coderd/gitsshkey_test.go @@ -113,7 +113,7 @@ func TestAgentGitSSHKey(t *testing.T) { }) project := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID) + workspace := coderdtest.CreateWorkspace(t, client, project.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) agentClient := agentsdk.New(client.URL) diff --git a/coderd/insights_test.go b/coderd/insights_test.go index 2447ec37f3516..20d1517d312ec 100644 --- a/coderd/insights_test.go +++ b/coderd/insights_test.go @@ -73,7 +73,7 @@ func TestDeploymentInsights(t *testing.T) { require.Empty(t, template.BuildTimeStats[codersdk.WorkspaceTransitionStart]) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx := testutil.Context(t, testutil.WaitLong) @@ -155,7 +155,7 @@ func TestUserActivityInsights_SanityCheck(t *testing.T) { require.Empty(t, template.BuildTimeStats[codersdk.WorkspaceTransitionStart]) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Start an agent so that we can generate stats. @@ -253,7 +253,7 @@ func TestUserLatencyInsights(t *testing.T) { require.Empty(t, template.BuildTimeStats[codersdk.WorkspaceTransitionStart]) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Start an agent so that we can generate stats. @@ -609,7 +609,7 @@ func TestTemplateInsights_Golden(t *testing.T) { createWorkspaces = append(createWorkspaces, func(templateID uuid.UUID) { // Create workspace using the users client. - createdWorkspace := coderdtest.CreateWorkspace(t, user.client, firstUser.OrganizationID, templateID, func(cwr *codersdk.CreateWorkspaceRequest) { + createdWorkspace := coderdtest.CreateWorkspace(t, user.client, templateID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.RichParameterValues = buildParameters }) workspace.id = createdWorkspace.ID @@ -1518,7 +1518,7 @@ func TestUserActivityInsights_Golden(t *testing.T) { createWorkspaces = append(createWorkspaces, func(templateID uuid.UUID) { // Create workspace using the users client. - createdWorkspace := coderdtest.CreateWorkspace(t, user.client, firstUser.OrganizationID, templateID) + createdWorkspace := coderdtest.CreateWorkspace(t, user.client, templateID) workspace.id = createdWorkspace.ID waitWorkspaces = append(waitWorkspaces, func() { coderdtest.AwaitWorkspaceBuildJobCompleted(t, user.client, createdWorkspace.LatestBuild.ID) diff --git a/coderd/prometheusmetrics/prometheusmetrics_test.go b/coderd/prometheusmetrics/prometheusmetrics_test.go index 8a4a152a86b4c..f5ed96f64dc41 100644 --- a/coderd/prometheusmetrics/prometheusmetrics_test.go +++ b/coderd/prometheusmetrics/prometheusmetrics_test.go @@ -310,7 +310,7 @@ func TestAgents(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // given @@ -616,7 +616,7 @@ func prepareWorkspaceAndAgent(ctx context.Context, t *testing.T, client *codersd }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.Name = fmt.Sprintf("workspace-%d", workspaceNum) }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) diff --git a/coderd/provisionerjobs_test.go b/coderd/provisionerjobs_test.go index 2dc5db3bf8efb..cf17d6495cfed 100644 --- a/coderd/provisionerjobs_test.go +++ b/coderd/provisionerjobs_test.go @@ -35,7 +35,7 @@ func TestProvisionerJobLogs(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -74,7 +74,7 @@ func TestProvisionerJobLogs(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() diff --git a/coderd/templates_test.go b/coderd/templates_test.go index c27a8a616b896..9e20557cafd49 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -1194,7 +1194,7 @@ func TestDeleteTemplate(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + coderdtest.CreateWorkspace(t, client, template.ID) ctx := testutil.Context(t, testutil.WaitLong) @@ -1228,7 +1228,7 @@ func TestTemplateMetrics(t *testing.T) { require.Empty(t, template.BuildTimeStats[codersdk.WorkspaceTransitionStart]) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) _ = agenttest.New(t, client.URL, authToken) diff --git a/coderd/templateversions_test.go b/coderd/templateversions_test.go index 1267213932649..cd54bfdaeaba7 100644 --- a/coderd/templateversions_test.go +++ b/coderd/templateversions_test.go @@ -1597,7 +1597,7 @@ func TestTemplateArchiveVersions(t *testing.T) { req.TemplateID = template.ID }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, used.ID) - workspace := coderdtest.CreateWorkspace(t, client, owner.OrganizationID, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, client, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) { request.TemplateVersionID = used.ID }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) diff --git a/coderd/users_test.go b/coderd/users_test.go index 7c19096105a95..0985c17fafd22 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -355,7 +355,7 @@ func TestDeleteUser(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - coderdtest.CreateWorkspace(t, anotherClient, user.OrganizationID, template.ID) + coderdtest.CreateWorkspace(t, anotherClient, template.ID) err := client.DeleteUser(context.Background(), another.ID) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) @@ -1486,7 +1486,7 @@ func TestWorkspacesByUser(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + coderdtest.CreateWorkspace(t, client, template.ID) res, err := newUserClient.Workspaces(ctx, codersdk.WorkspaceFilter{Owner: codersdk.Me}) require.NoError(t, err) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index a2915d2633f13..12d1d591fd46d 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -364,7 +364,7 @@ func TestWorkspaceAgentConnectRPC(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) version = coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ diff --git a/coderd/workspaceapps/apptest/setup.go b/coderd/workspaceapps/apptest/setup.go index c27032c192b91..6708be1e700bd 100644 --- a/coderd/workspaceapps/apptest/setup.go +++ b/coderd/workspaceapps/apptest/setup.go @@ -388,7 +388,7 @@ func createWorkspaceWithApps(t *testing.T, client *codersdk.Client, orgID uuid.U }) template := coderdtest.CreateTemplate(t, client, orgID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, orgID, template.ID, workspaceMutators...) + workspace := coderdtest.CreateWorkspace(t, client, template.ID, workspaceMutators...) workspaceBuild := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Verify app subdomains diff --git a/coderd/workspaceapps/db_test.go b/coderd/workspaceapps/db_test.go index e8c7464f88ff1..6c5a0212aff2b 100644 --- a/coderd/workspaceapps/db_test.go +++ b/coderd/workspaceapps/db_test.go @@ -198,7 +198,7 @@ func Test_ResolveRequest(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, firstUser.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, firstUser.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) _ = agenttest.New(t, client.URL, agentAuthToken) diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 389e0563f46f8..757dac7fb6326 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -61,7 +61,7 @@ func TestWorkspaceBuild(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) auditor.ResetLogs() - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Create workspace will also start a build, so we need to wait for // it to ensure all events are recorded. @@ -92,7 +92,7 @@ func TestWorkspaceBuildByBuildNumber(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) _, err = client.WorkspaceBuildByUsernameAndWorkspaceNameAndBuildNumber( ctx, user.Username, @@ -115,7 +115,7 @@ func TestWorkspaceBuildByBuildNumber(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) _, err = client.WorkspaceBuildByUsernameAndWorkspaceNameAndBuildNumber( ctx, user.Username, @@ -141,7 +141,7 @@ func TestWorkspaceBuildByBuildNumber(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) _, err = client.WorkspaceBuildByUsernameAndWorkspaceNameAndBuildNumber( ctx, user.Username, @@ -167,7 +167,7 @@ func TestWorkspaceBuildByBuildNumber(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) _, err = client.WorkspaceBuildByUsernameAndWorkspaceNameAndBuildNumber( ctx, user.Username, @@ -196,7 +196,7 @@ func TestWorkspaceBuilds(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) builds, err := client.WorkspaceBuilds(ctx, codersdk.WorkspaceBuildsRequest{WorkspaceID: workspace.ID}) require.Len(t, builds, 1) @@ -256,7 +256,7 @@ func TestWorkspaceBuilds(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -281,7 +281,7 @@ func TestWorkspaceBuilds(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) var expectedBuilds []codersdk.WorkspaceBuild extraBuilds := 4 @@ -330,7 +330,7 @@ func TestWorkspaceBuildsProvisionerState(t *testing.T) { template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) build, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ @@ -346,7 +346,7 @@ func TestWorkspaceBuildsProvisionerState(t *testing.T) { // state. regularUser, _ := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) - workspace = coderdtest.CreateWorkspace(t, regularUser, first.OrganizationID, template.ID) + workspace = coderdtest.CreateWorkspace(t, regularUser, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, regularUser, workspace.LatestBuild.ID) _, err = regularUser.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ @@ -375,7 +375,7 @@ func TestWorkspaceBuildsProvisionerState(t *testing.T) { template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Providing both state and orphan fails. @@ -422,7 +422,7 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) var build codersdk.WorkspaceBuild ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -467,7 +467,7 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) { template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) userClient, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) - workspace := coderdtest.CreateWorkspace(t, userClient, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, userClient, template.ID) var build codersdk.WorkspaceBuild ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -540,7 +540,7 @@ func TestWorkspaceBuildResources(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -597,7 +597,7 @@ func TestWorkspaceBuildLogs(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -635,7 +635,7 @@ func TestWorkspaceBuildState(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -663,7 +663,7 @@ func TestWorkspaceBuildStatus(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) numLogs++ // add an audit log for template creation - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) numLogs++ // add an audit log for workspace creation // initial returned state is "pending" @@ -765,7 +765,7 @@ func TestWorkspaceDeleteSuspendedUser(t *testing.T) { validateCalls = 0 // Reset coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) require.Equal(t, 1, validateCalls) // Ensure the external link is working @@ -805,7 +805,7 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, adminClient, version.ID) // Template author: create a workspace - workspace := coderdtest.CreateWorkspace(t, adminClient, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, adminClient, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, adminClient, workspace.LatestBuild.ID) // Template author: try to start a workspace build in debug mode @@ -842,7 +842,7 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, templateAuthorClient, version.ID) // Regular user: create a workspace - workspace := coderdtest.CreateWorkspace(t, regularUserClient, templateAuthor.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, regularUserClient, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, regularUserClient, workspace.LatestBuild.ID) // Regular user: try to start a workspace build in debug mode @@ -879,7 +879,7 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, templateAuthorClient, version.ID) // Template author: create a workspace - workspace := coderdtest.CreateWorkspace(t, templateAuthorClient, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, templateAuthorClient, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, templateAuthorClient, workspace.LatestBuild.ID) // Template author: try to start a workspace build in debug mode @@ -945,7 +945,7 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, adminClient, version.ID) // Create workspace - workspace := coderdtest.CreateWorkspace(t, adminClient, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, adminClient, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, adminClient, workspace.LatestBuild.ID) // Create workspace build @@ -1005,7 +1005,7 @@ func TestPostWorkspaceBuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -1053,7 +1053,7 @@ func TestPostWorkspaceBuild(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) closer.Close() // Close here so workspace build doesn't process! - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -1083,7 +1083,7 @@ func TestPostWorkspaceBuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -1111,7 +1111,7 @@ func TestPostWorkspaceBuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -1134,7 +1134,7 @@ func TestPostWorkspaceBuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) wantState := []byte("something") _ = closeDaemon.Close() @@ -1160,7 +1160,7 @@ func TestPostWorkspaceBuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) diff --git a/coderd/workspaceresourceauth_test.go b/coderd/workspaceresourceauth_test.go index 99a8d558f54f2..d653231ab90d6 100644 --- a/coderd/workspaceresourceauth_test.go +++ b/coderd/workspaceresourceauth_test.go @@ -44,7 +44,7 @@ func TestPostWorkspaceAuthAzureInstanceIdentity(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -89,7 +89,7 @@ func TestPostWorkspaceAuthAWSInstanceIdentity(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -175,7 +175,7 @@ func TestPostWorkspaceAuthGoogleInstanceIdentity(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index ceba543639cc3..901e3723964bd 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -340,6 +340,7 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) // @Description specify either the Template ID or the Template Version ID, // @Description not both. If the Template ID is specified, the active version // @Description of the template will be used. +// @Deprecated Use /users/{user}/workspaces instead. // @ID create-user-workspace-by-organization // @Security CoderSessionToken // @Accept json @@ -353,9 +354,9 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request) func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Request) { var ( ctx = r.Context() - organization = httpmw.OrganizationParam(r) apiKey = httpmw.APIKey(r) auditor = api.Auditor.Load() + organization = httpmw.OrganizationParam(r) member = httpmw.OrganizationMemberParam(r) workspaceResourceInfo = audit.AdditionalFields{ WorkspaceOwner: member.Username, @@ -380,16 +381,90 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req return } - var createWorkspace codersdk.CreateWorkspaceRequest - if !httpapi.Read(ctx, rw, r, &createWorkspace) { + var req codersdk.CreateWorkspaceRequest + if !httpapi.Read(ctx, rw, r, &req) { return } + owner := workspaceOwner{ + ID: member.UserID, + Username: member.Username, + AvatarURL: member.AvatarURL, + } + + createWorkspace(ctx, aReq, apiKey.UserID, api, owner, req, rw, r) +} + +// Create a new workspace for the currently authenticated user. +// +// @Summary Create user workspace +// @Description Create a new workspace using a template. The request must +// @Description specify either the Template ID or the Template Version ID, +// @Description not both. If the Template ID is specified, the active version +// @Description of the template will be used. +// @ID create-user-workspace +// @Security CoderSessionToken +// @Accept json +// @Produce json +// @Tags Workspaces +// @Param user path string true "Username, UUID, or me" +// @Param request body codersdk.CreateWorkspaceRequest true "Create workspace request" +// @Success 200 {object} codersdk.Workspace +// @Router /users/{user}/workspaces [post] +func (api *API) postUserWorkspaces(rw http.ResponseWriter, r *http.Request) { + var ( + ctx = r.Context() + apiKey = httpmw.APIKey(r) + auditor = api.Auditor.Load() + user = httpmw.UserParam(r) + ) + + aReq, commitAudit := audit.InitRequest[database.Workspace](rw, &audit.RequestParams{ + Audit: *auditor, + Log: api.Logger, + Request: r, + Action: database.AuditActionCreate, + AdditionalFields: audit.AdditionalFields{ + WorkspaceOwner: user.Username, + }, + }) + + defer commitAudit() + + var req codersdk.CreateWorkspaceRequest + if !httpapi.Read(ctx, rw, r, &req) { + return + } + + owner := workspaceOwner{ + ID: user.ID, + Username: user.Username, + AvatarURL: user.AvatarURL, + } + createWorkspace(ctx, aReq, apiKey.UserID, api, owner, req, rw, r) +} + +type workspaceOwner struct { + ID uuid.UUID + Username string + AvatarURL string +} + +func createWorkspace( + ctx context.Context, + auditReq *audit.Request[database.Workspace], + initiatorID uuid.UUID, + api *API, + owner workspaceOwner, + req codersdk.CreateWorkspaceRequest, + rw http.ResponseWriter, + r *http.Request, +) { // If we were given a `TemplateVersionID`, we need to determine the `TemplateID` from it. - templateID := createWorkspace.TemplateID + templateID := req.TemplateID if templateID == uuid.Nil { - templateVersion, err := api.Database.GetTemplateVersionByID(ctx, createWorkspace.TemplateVersionID) - if errors.Is(err, sql.ErrNoRows) { + templateVersion, err := api.Database.GetTemplateVersionByID(ctx, req.TemplateVersionID) + if httpapi.Is404Error(err) { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: fmt.Sprintf("Template version %q doesn't exist.", templateID.String()), Validations: []codersdk.ValidationError{{ @@ -423,7 +498,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req } template, err := api.Database.GetTemplateByID(ctx, templateID) - if errors.Is(err, sql.ErrNoRows) { + if httpapi.Is404Error(err) { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: fmt.Sprintf("Template %q doesn't exist.", templateID.String()), Validations: []codersdk.ValidationError{{ @@ -447,6 +522,17 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req return } + // Update audit log's organization + auditReq.UpdateOrganizationID(template.OrganizationID) + + // Do this upfront to save work. If this fails, the rest of the work + // would be wasted. + if !api.Authorize(r, policy.ActionCreate, + rbac.ResourceWorkspace.InOrg(template.OrganizationID).WithOwner(owner.ID.String())) { + httpapi.ResourceNotFound(rw) + return + } + templateAccessControl := (*(api.AccessControlStore.Load())).GetTemplateAccessControl(template) if templateAccessControl.IsDeprecated() { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ @@ -458,14 +544,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req return } - if organization.ID != template.OrganizationID { - httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{ - Message: fmt.Sprintf("Template is not in organization %q.", organization.Name), - }) - return - } - - dbAutostartSchedule, err := validWorkspaceSchedule(createWorkspace.AutostartSchedule) + dbAutostartSchedule, err := validWorkspaceSchedule(req.AutostartSchedule) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid Autostart Schedule.", @@ -483,7 +562,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req return } - dbTTL, err := validWorkspaceTTLMillis(createWorkspace.TTLMillis, templateSchedule.DefaultTTL) + dbTTL, err := validWorkspaceTTLMillis(req.TTLMillis, templateSchedule.DefaultTTL) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid Workspace Time to Shutdown.", @@ -494,8 +573,8 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req // back-compatibility: default to "never" if not included. dbAU := database.AutomaticUpdatesNever - if createWorkspace.AutomaticUpdates != "" { - dbAU, err = validWorkspaceAutomaticUpdates(createWorkspace.AutomaticUpdates) + if req.AutomaticUpdates != "" { + dbAU, err = validWorkspaceAutomaticUpdates(req.AutomaticUpdates) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid Workspace Automatic Updates setting.", @@ -509,13 +588,13 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req // read other workspaces. Ideally we check the error on create and look for // a postgres conflict error. workspace, err := api.Database.GetWorkspaceByOwnerIDAndName(ctx, database.GetWorkspaceByOwnerIDAndNameParams{ - OwnerID: member.UserID, - Name: createWorkspace.Name, + OwnerID: owner.ID, + Name: req.Name, }) if err == nil { // If the workspace already exists, don't allow creation. httpapi.Write(ctx, rw, http.StatusConflict, codersdk.Response{ - Message: fmt.Sprintf("Workspace %q already exists.", createWorkspace.Name), + Message: fmt.Sprintf("Workspace %q already exists.", req.Name), Validations: []codersdk.ValidationError{{ Field: "name", Detail: "This value is already in use and should be unique.", @@ -525,7 +604,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req } if err != nil && !errors.Is(err, sql.ErrNoRows) { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: fmt.Sprintf("Internal error fetching workspace by name %q.", createWorkspace.Name), + Message: fmt.Sprintf("Internal error fetching workspace by name %q.", req.Name), Detail: err.Error(), }) return @@ -542,10 +621,10 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req ID: uuid.New(), CreatedAt: now, UpdatedAt: now, - OwnerID: member.UserID, + OwnerID: owner.ID, OrganizationID: template.OrganizationID, TemplateID: template.ID, - Name: createWorkspace.Name, + Name: req.Name, AutostartSchedule: dbAutostartSchedule, Ttl: dbTTL, // The workspaces page will sort by last used at, and it's useful to @@ -559,11 +638,11 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req builder := wsbuilder.New(workspace, database.WorkspaceTransitionStart). Reason(database.BuildReasonInitiator). - Initiator(apiKey.UserID). + Initiator(initiatorID). ActiveVersion(). - RichParameterValues(createWorkspace.RichParameterValues) - if createWorkspace.TemplateVersionID != uuid.Nil { - builder = builder.VersionID(createWorkspace.TemplateVersionID) + RichParameterValues(req.RichParameterValues) + if req.TemplateVersionID != uuid.Nil { + builder = builder.VersionID(req.TemplateVersionID) } workspaceBuild, provisionerJob, err = builder.Build( @@ -596,7 +675,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req // Client probably doesn't care about this error, so just log it. api.Logger.Error(ctx, "failed to post provisioner job to pubsub", slog.Error(err)) } - aReq.New = workspace + auditReq.New = workspace api.Telemetry.Report(&telemetry.Snapshot{ Workspaces: []telemetry.Workspace{telemetry.ConvertWorkspace(workspace)}, @@ -610,8 +689,8 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req ProvisionerJob: *provisionerJob, QueuePosition: 0, }, - member.Username, - member.AvatarURL, + owner.Username, + owner.AvatarURL, []database.WorkspaceResource{}, []database.WorkspaceResourceMetadatum{}, []database.WorkspaceAgent{}, @@ -629,12 +708,12 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req } w, err := convertWorkspace( - apiKey.UserID, + initiatorID, workspace, apiBuild, template, - member.Username, - member.AvatarURL, + owner.Username, + owner.AvatarURL, api.Options.AllowWorkspaceRenames, ) if err != nil { diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 94e89bcd50f98..8d1c97dfcf207 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -55,7 +55,7 @@ func TestWorkspace(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -79,7 +79,7 @@ func TestWorkspace(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -117,8 +117,8 @@ func TestWorkspace(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - ws1 := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - ws2 := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws1 := coderdtest.CreateWorkspace(t, client, template.ID) + ws2 := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws1.LatestBuild.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws2.LatestBuild.ID) @@ -156,7 +156,7 @@ func TestWorkspace(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - ws1 := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws1 := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws1.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium) @@ -188,7 +188,7 @@ func TestWorkspace(t *testing.T) { require.NotEmpty(t, template.DisplayName) require.NotEmpty(t, template.Icon) require.False(t, template.AllowUserCancelWorkspaceJobs) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -229,7 +229,7 @@ func TestWorkspace(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -270,7 +270,7 @@ func TestWorkspace(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -319,7 +319,7 @@ func TestWorkspace(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -557,7 +557,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -580,7 +580,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) assert.True(t, auditor.Contains(t, database.AuditLog{ ResourceType: database.ResourceTypeWorkspace, @@ -599,10 +599,10 @@ func TestPostWorkspacesByOrganization(t *testing.T) { versionTest := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, nil, template.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, versionDefault.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, versionTest.ID) - defaultWorkspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, uuid.Nil, + defaultWorkspace := coderdtest.CreateWorkspace(t, client, uuid.Nil, func(c *codersdk.CreateWorkspaceRequest) { c.TemplateVersionID = versionDefault.ID }, ) - testWorkspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, uuid.Nil, + testWorkspace := coderdtest.CreateWorkspace(t, client, uuid.Nil, func(c *codersdk.CreateWorkspaceRequest) { c.TemplateVersionID = versionTest.ID }, ) defaultWorkspaceBuild := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, defaultWorkspace.LatestBuild.ID) @@ -678,7 +678,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) // When: we create a workspace with autostop not enabled - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.TTLMillis = ptr.Ref(int64(0)) }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) @@ -697,7 +697,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { ctr.DefaultTTLMillis = ptr.Ref(templateTTL) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.TTLMillis = nil // ensure that no default TTL is set }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) @@ -790,7 +790,7 @@ func TestWorkspaceByOwnerAndName(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -805,7 +805,7 @@ func TestWorkspaceByOwnerAndName(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -1131,7 +1131,7 @@ func TestWorkspaceFilter(t *testing.T) { } availTemplates = append(availTemplates, template) - workspace := coderdtest.CreateWorkspace(t, user.Client, template.OrganizationID, template.ID, func(request *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, user.Client, template.ID, func(request *codersdk.CreateWorkspaceRequest) { if count%3 == 0 { request.Name = strings.ToUpper(request.Name) } @@ -1145,7 +1145,7 @@ func TestWorkspaceFilter(t *testing.T) { // Make a workspace with a random template idx, _ := cryptorand.Intn(len(availTemplates)) randTemplate := availTemplates[idx] - randWorkspace := coderdtest.CreateWorkspace(t, user.Client, randTemplate.OrganizationID, randTemplate.ID) + randWorkspace := coderdtest.CreateWorkspace(t, user.Client, randTemplate.ID) allWorkspaces = append(allWorkspaces, madeWorkspace{ Workspace: randWorkspace, Template: randTemplate, @@ -1285,7 +1285,7 @@ func TestWorkspaceFilterManual(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -1320,8 +1320,8 @@ func TestWorkspaceFilterManual(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - alpha := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - bravo := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + alpha := coderdtest.CreateWorkspace(t, client, template.ID) + bravo := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -1356,8 +1356,8 @@ func TestWorkspaceFilterManual(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version2.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) template2 := coderdtest.CreateTemplate(t, client, user.OrganizationID, version2.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - _ = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template2.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) + _ = coderdtest.CreateWorkspace(t, client, template2.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -1383,8 +1383,8 @@ func TestWorkspaceFilterManual(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace1 := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - workspace2 := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace1 := coderdtest.CreateWorkspace(t, client, template.ID) + workspace2 := coderdtest.CreateWorkspace(t, client, template.ID) // wait for workspaces to be "running" _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace1.LatestBuild.ID) @@ -1431,8 +1431,8 @@ func TestWorkspaceFilterManual(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version2.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) template2 := coderdtest.CreateTemplate(t, client, user.OrganizationID, version2.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - _ = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template2.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) + _ = coderdtest.CreateWorkspace(t, client, template2.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -1464,7 +1464,7 @@ func TestWorkspaceFilterManual(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -1492,7 +1492,7 @@ func TestWorkspaceFilterManual(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) _ = agenttest.New(t, client.URL, authToken) @@ -1539,7 +1539,7 @@ func TestWorkspaceFilterManual(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium) @@ -1620,10 +1620,10 @@ func TestWorkspaceFilterManual(t *testing.T) { defer cancel() now := dbtime.Now() - before := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + before := coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, before.LatestBuild.ID) - after := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + after := coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, after.LatestBuild.ID) //nolint:gocritic // Unit testing context @@ -1662,7 +1662,7 @@ func TestWorkspaceFilterManual(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -1746,7 +1746,7 @@ func TestWorkspaceFilterManual(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, noOptionalVersion.ID) // foo :: one=foo, two=bar, one=baz, optional=optional - foo := coderdtest.CreateWorkspace(t, client, user.OrganizationID, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) { + foo := coderdtest.CreateWorkspace(t, client, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) { request.TemplateVersionID = version.ID request.RichParameterValues = []codersdk.WorkspaceBuildParameter{ { @@ -1769,7 +1769,7 @@ func TestWorkspaceFilterManual(t *testing.T) { }) // bar :: one=foo, two=bar, three=baz, optional=optional - bar := coderdtest.CreateWorkspace(t, client, user.OrganizationID, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) { + bar := coderdtest.CreateWorkspace(t, client, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) { request.TemplateVersionID = version.ID request.RichParameterValues = []codersdk.WorkspaceBuildParameter{ { @@ -1792,7 +1792,7 @@ func TestWorkspaceFilterManual(t *testing.T) { }) // baz :: one=baz, two=baz, three=baz - baz := coderdtest.CreateWorkspace(t, client, user.OrganizationID, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) { + baz := coderdtest.CreateWorkspace(t, client, uuid.Nil, func(request *codersdk.CreateWorkspaceRequest) { request.TemplateVersionID = noOptionalVersion.ID request.RichParameterValues = []codersdk.WorkspaceBuildParameter{ { @@ -1882,9 +1882,9 @@ func TestOffsetLimit(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - _ = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - _ = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) - _ = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + _ = coderdtest.CreateWorkspace(t, client, template.ID) + _ = coderdtest.CreateWorkspace(t, client, template.ID) + _ = coderdtest.CreateWorkspace(t, client, template.ID) // Case 1: empty finds all workspaces ws, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{}) @@ -2000,7 +2000,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace = coderdtest.CreateWorkspace(t, client, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = nil cwr.TTLMillis = nil }) @@ -2079,7 +2079,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace = coderdtest.CreateWorkspace(t, client, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = nil cwr.TTLMillis = nil }) @@ -2185,7 +2185,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, mutators...) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace = coderdtest.CreateWorkspace(t, client, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = nil cwr.TTLMillis = nil }) @@ -2246,7 +2246,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace = coderdtest.CreateWorkspace(t, client, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = nil cwr.TTLMillis = nil }) @@ -2299,7 +2299,7 @@ func TestWorkspaceExtend(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace = coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.TTLMillis = ptr.Ref(ttl.Milliseconds()) }) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) @@ -2367,7 +2367,7 @@ func TestWorkspaceUpdateAutomaticUpdates_OK(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, adminClient, admin.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, adminClient, version.ID) project = coderdtest.CreateTemplate(t, adminClient, admin.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, admin.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace = coderdtest.CreateWorkspace(t, client, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = nil cwr.TTLMillis = nil cwr.AutomaticUpdates = codersdk.AutomaticUpdatesNever @@ -2459,7 +2459,7 @@ func TestWorkspaceWatcher(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -2618,7 +2618,7 @@ func TestWorkspaceResource(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -2678,7 +2678,7 @@ func TestWorkspaceResource(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -2752,7 +2752,7 @@ func TestWorkspaceResource(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -2807,7 +2807,7 @@ func TestWorkspaceResource(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -2911,7 +2911,7 @@ func TestWorkspaceWithRichParameters(t *testing.T) { } template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.RichParameterValues = expectedBuildParameters }) @@ -2989,7 +2989,7 @@ func TestWorkspaceWithOptionalRichParameters(t *testing.T) { require.Equal(t, secondParameterRequired, templateRichParameters[1].Required) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.RichParameterValues = []codersdk.WorkspaceBuildParameter{ // First parameter is optional, so coder will pick the default value. {Name: secondParameterName, Value: secondParameterValue}, @@ -3069,7 +3069,7 @@ func TestWorkspaceWithEphemeralRichParameters(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) // Create workspace with default values - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) workspaceBuild := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) @@ -3155,7 +3155,7 @@ func TestWorkspaceDormant(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantAutoDeleteMillis = ptr.Ref[int64](timeTilDormantAutoDelete.Milliseconds()) }) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -3205,7 +3205,7 @@ func TestWorkspaceDormant(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace = coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ) @@ -3462,7 +3462,7 @@ func TestNotifications(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace = coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ) @@ -3499,7 +3499,7 @@ func TestNotifications(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace = coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ) @@ -3530,7 +3530,7 @@ func TestNotifications(t *testing.T) { version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace = coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ) diff --git a/codersdk/organizations.go b/codersdk/organizations.go index 750df452f953f..277d41cf9ae52 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -473,8 +473,15 @@ func (c *Client) TemplateByName(ctx context.Context, organizationID uuid.UUID, n } // CreateWorkspace creates a new workspace for the template specified. -func (c *Client) CreateWorkspace(ctx context.Context, organizationID uuid.UUID, user string, request CreateWorkspaceRequest) (Workspace, error) { - res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/organizations/%s/members/%s/workspaces", organizationID, user), request) +// +// Deprecated: Use CreateUserWorkspace instead. +func (c *Client) CreateWorkspace(ctx context.Context, _ uuid.UUID, user string, request CreateWorkspaceRequest) (Workspace, error) { + return c.CreateUserWorkspace(ctx, user, request) +} + +// CreateUserWorkspace creates a new workspace for the template specified. +func (c *Client) CreateUserWorkspace(ctx context.Context, user string, request CreateWorkspaceRequest) (Workspace, error) { + res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/users/%s/workspaces", user), request) if err != nil { return Workspace{}, err } diff --git a/docs/api/workspaces.md b/docs/api/workspaces.md index ddaa70c9df292..10d4680430834 100644 --- a/docs/api/workspaces.md +++ b/docs/api/workspaces.md @@ -455,6 +455,245 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Create user workspace + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/users/{user}/workspaces \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /users/{user}/workspaces` + +Create a new workspace using a template. The request must +specify either the Template ID or the Template Version ID, +not both. If the Template ID is specified, the active version +of the template will be used. + +> Body parameter + +```json +{ + "automatic_updates": "always", + "autostart_schedule": "string", + "name": "string", + "rich_parameter_values": [ + { + "name": "string", + "value": "string" + } + ], + "template_id": "c6d67e98-83ea-49f0-8812-e4abae2b68bc", + "template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1", + "ttl_ms": 0 +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +| ------ | ---- | ---------------------------------------------------------------------------- | -------- | ------------------------ | +| `user` | path | string | true | Username, UUID, or me | +| `body` | body | [codersdk.CreateWorkspaceRequest](schemas.md#codersdkcreateworkspacerequest) | true | Create workspace request | + +### Example responses + +> 200 Response + +```json +{ + "allow_renames": true, + "automatic_updates": "always", + "autostart_schedule": "string", + "created_at": "2019-08-24T14:15:22Z", + "deleting_at": "2019-08-24T14:15:22Z", + "dormant_at": "2019-08-24T14:15:22Z", + "favorite": true, + "health": { + "failing_agents": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], + "healthy": false + }, + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "last_used_at": "2019-08-24T14:15:22Z", + "latest_build": { + "build_number": 0, + "created_at": "2019-08-24T14:15:22Z", + "daily_cost": 0, + "deadline": "2019-08-24T14:15:22Z", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "initiator_id": "06588898-9a84-4b35-ba8f-f9cbd64946f3", + "initiator_name": "string", + "job": { + "canceled_at": "2019-08-24T14:15:22Z", + "completed_at": "2019-08-24T14:15:22Z", + "created_at": "2019-08-24T14:15:22Z", + "error": "string", + "error_code": "REQUIRED_TEMPLATE_VARIABLES", + "file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "queue_position": 0, + "queue_size": 0, + "started_at": "2019-08-24T14:15:22Z", + "status": "pending", + "tags": { + "property1": "string", + "property2": "string" + }, + "worker_id": "ae5fa6f7-c55b-40c1-b40a-b36ac467652b" + }, + "max_deadline": "2019-08-24T14:15:22Z", + "reason": "initiator", + "resources": [ + { + "agents": [ + { + "api_version": "string", + "apps": [ + { + "command": "string", + "display_name": "string", + "external": true, + "health": "disabled", + "healthcheck": { + "interval": 0, + "threshold": 0, + "url": "string" + }, + "icon": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "sharing_level": "owner", + "slug": "string", + "subdomain": true, + "subdomain_name": "string", + "url": "string" + } + ], + "architecture": "string", + "connection_timeout_seconds": 0, + "created_at": "2019-08-24T14:15:22Z", + "directory": "string", + "disconnected_at": "2019-08-24T14:15:22Z", + "display_apps": ["vscode"], + "environment_variables": { + "property1": "string", + "property2": "string" + }, + "expanded_directory": "string", + "first_connected_at": "2019-08-24T14:15:22Z", + "health": { + "healthy": false, + "reason": "agent has lost connection" + }, + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "instance_id": "string", + "last_connected_at": "2019-08-24T14:15:22Z", + "latency": { + "property1": { + "latency_ms": 0, + "preferred": true + }, + "property2": { + "latency_ms": 0, + "preferred": true + } + }, + "lifecycle_state": "created", + "log_sources": [ + { + "created_at": "2019-08-24T14:15:22Z", + "display_name": "string", + "icon": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "workspace_agent_id": "7ad2e618-fea7-4c1a-b70a-f501566a72f1" + } + ], + "logs_length": 0, + "logs_overflowed": true, + "name": "string", + "operating_system": "string", + "ready_at": "2019-08-24T14:15:22Z", + "resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f", + "scripts": [ + { + "cron": "string", + "log_path": "string", + "log_source_id": "4197ab25-95cf-4b91-9c78-f7f2af5d353a", + "run_on_start": true, + "run_on_stop": true, + "script": "string", + "start_blocks_login": true, + "timeout": 0 + } + ], + "started_at": "2019-08-24T14:15:22Z", + "startup_script_behavior": "blocking", + "status": "connecting", + "subsystems": ["envbox"], + "troubleshooting_url": "string", + "updated_at": "2019-08-24T14:15:22Z", + "version": "string" + } + ], + "created_at": "2019-08-24T14:15:22Z", + "daily_cost": 0, + "hide": true, + "icon": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "job_id": "453bd7d7-5355-4d6d-a38e-d9e7eb218c3f", + "metadata": [ + { + "key": "string", + "sensitive": true, + "value": "string" + } + ], + "name": "string", + "type": "string", + "workspace_transition": "start" + } + ], + "status": "pending", + "template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1", + "template_version_name": "string", + "transition": "start", + "updated_at": "2019-08-24T14:15:22Z", + "workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9", + "workspace_name": "string", + "workspace_owner_avatar_url": "string", + "workspace_owner_id": "e7078695-5279-4c86-8774-3ac2367a2fc7", + "workspace_owner_name": "string" + }, + "name": "string", + "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "organization_name": "string", + "outdated": true, + "owner_avatar_url": "string", + "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05", + "owner_name": "string", + "template_active_version_id": "b0da9c29-67d8-4c87-888c-bafe356f7f3c", + "template_allow_user_cancel_workspace_jobs": true, + "template_display_name": "string", + "template_icon": "string", + "template_id": "c6d67e98-83ea-49f0-8812-e4abae2b68bc", + "template_name": "string", + "template_require_active_version": true, + "ttl_ms": 0, + "updated_at": "2019-08-24T14:15:22Z" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +| ------ | ------------------------------------------------------- | ----------- | -------------------------------------------------- | +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Workspace](schemas.md#codersdkworkspace) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## List workspaces ### Code samples diff --git a/enterprise/cli/start_test.go b/enterprise/cli/start_test.go index 123da3a17786b..dd86b20d44fb6 100644 --- a/enterprise/cli/start_test.go +++ b/enterprise/cli/start_test.go @@ -196,7 +196,7 @@ func TestStart(t *testing.T) { template := coderdtest.CreateTemplate(t, ownerClient, owner.OrganizationID, version.ID) memberClient, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) - workspace := coderdtest.CreateWorkspace(t, memberClient, owner.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, memberClient, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, memberClient, workspace.LatestBuild.ID) _ = coderdtest.MustTransitionWorkspace(t, memberClient, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop) err := memberClient.UpdateWorkspaceDormancy(ctx, workspace.ID, codersdk.UpdateWorkspaceDormancy{ diff --git a/enterprise/coderd/provisionerdaemons_test.go b/enterprise/coderd/provisionerdaemons_test.go index de418e3e81028..d92e278d8eb15 100644 --- a/enterprise/coderd/provisionerdaemons_test.go +++ b/enterprise/coderd/provisionerdaemons_test.go @@ -306,7 +306,7 @@ func TestProvisionerDaemonServe(t *testing.T) { provisionersdk.TagScope: provisionersdk.ScopeUser, }) defer closer.Close() - workspace := coderdtest.CreateWorkspace(t, another, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, another, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) }) @@ -436,7 +436,7 @@ func TestProvisionerDaemonServe(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) diff --git a/enterprise/coderd/templates_test.go b/enterprise/coderd/templates_test.go index fedef4edde012..99e99fe6cb31b 100644 --- a/enterprise/coderd/templates_test.go +++ b/enterprise/coderd/templates_test.go @@ -134,7 +134,7 @@ func TestTemplates(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) ws, err := client.Workspace(context.Background(), ws.ID) require.NoError(t, err) @@ -467,8 +467,8 @@ func TestTemplates(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - activeWS := coderdtest.CreateWorkspace(t, anotherClient, user.OrganizationID, template.ID) - dormantWS := coderdtest.CreateWorkspace(t, anotherClient, user.OrganizationID, template.ID) + activeWS := coderdtest.CreateWorkspace(t, anotherClient, template.ID) + dormantWS := coderdtest.CreateWorkspace(t, anotherClient, template.ID) require.Nil(t, activeWS.DeletingAt) require.Nil(t, dormantWS.DeletingAt) @@ -541,8 +541,8 @@ func TestTemplates(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - activeWS := coderdtest.CreateWorkspace(t, anotherClient, user.OrganizationID, template.ID) - dormantWS := coderdtest.CreateWorkspace(t, anotherClient, user.OrganizationID, template.ID) + activeWS := coderdtest.CreateWorkspace(t, anotherClient, template.ID) + dormantWS := coderdtest.CreateWorkspace(t, anotherClient, template.ID) require.Nil(t, activeWS.DeletingAt) require.Nil(t, dormantWS.DeletingAt) @@ -599,8 +599,8 @@ func TestTemplates(t *testing.T) { coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - activeWorkspace := coderdtest.CreateWorkspace(t, anotherClient, user.OrganizationID, template.ID) - dormantWorkspace := coderdtest.CreateWorkspace(t, anotherClient, user.OrganizationID, template.ID) + activeWorkspace := coderdtest.CreateWorkspace(t, anotherClient, template.ID) + dormantWorkspace := coderdtest.CreateWorkspace(t, anotherClient, template.ID) require.Nil(t, activeWorkspace.DeletingAt) require.Nil(t, dormantWorkspace.DeletingAt) diff --git a/enterprise/coderd/workspaceagents_test.go b/enterprise/coderd/workspaceagents_test.go index 12c308987fd14..ac73b0867ceb8 100644 --- a/enterprise/coderd/workspaceagents_test.go +++ b/enterprise/coderd/workspaceagents_test.go @@ -124,7 +124,7 @@ func setupWorkspaceAgent(t *testing.T, client *codersdk.Client, user codersdk.Cr }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) agentClient := agentsdk.New(client.URL) agentClient.SDK.HTTPClient = &http.Client{ diff --git a/enterprise/coderd/workspaceproxy_test.go b/enterprise/coderd/workspaceproxy_test.go index bafa3f93c2b1e..bf6e46c08dfb5 100644 --- a/enterprise/coderd/workspaceproxy_test.go +++ b/enterprise/coderd/workspaceproxy_test.go @@ -628,7 +628,7 @@ func TestIssueSignedAppToken(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) workspace.LatestBuild = build @@ -721,7 +721,7 @@ func TestReconnectingPTYSignedToken(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) workspace.LatestBuild = build diff --git a/enterprise/coderd/workspacequota_test.go b/enterprise/coderd/workspacequota_test.go index 2d99a4ce31ac5..4ebad488942f3 100644 --- a/enterprise/coderd/workspacequota_test.go +++ b/enterprise/coderd/workspacequota_test.go @@ -117,7 +117,7 @@ func TestWorkspaceQuota(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) assert.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) }() @@ -126,7 +126,7 @@ func TestWorkspaceQuota(t *testing.T) { verifyQuota(ctx, t, client, 4, 4) // Next one must fail - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) // Consumed shouldn't bump @@ -151,7 +151,7 @@ func TestWorkspaceQuota(t *testing.T) { } // Next one should now succeed - workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace = coderdtest.CreateWorkspace(t, client, template.ID) build = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) verifyQuota(ctx, t, client, 4, 4) @@ -202,7 +202,7 @@ func TestWorkspaceQuota(t *testing.T) { var wg sync.WaitGroup var workspaces []codersdk.Workspace for i := 0; i < 2; i++ { - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) workspaces = append(workspaces, workspace) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) assert.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) @@ -211,7 +211,7 @@ func TestWorkspaceQuota(t *testing.T) { verifyQuota(ctx, t, client, 4, 4) // Next one must fail - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) require.Contains(t, build.Job.Error, "quota") diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go index bef6bd0ded662..0b758e0491e1b 100644 --- a/enterprise/coderd/workspaces_test.go +++ b/enterprise/coderd/workspaces_test.go @@ -83,7 +83,7 @@ func TestCreateWorkspace(t *testing.T) { require.Error(t, err) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) - require.Equal(t, http.StatusForbidden, apiErr.StatusCode()) + require.Equal(t, http.StatusNotAcceptable, apiErr.StatusCode()) }) // Test that a user cannot indirectly access @@ -135,6 +135,151 @@ func TestCreateWorkspace(t *testing.T) { _, err = client1.CreateWorkspace(ctx, user.OrganizationID, user1.ID.String(), req) require.Error(t, err) }) + + t.Run("NoTemplateAccess", func(t *testing.T) { + t.Parallel() + ownerClient, owner := coderdenttest.New(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + IncludeProvisionerDaemon: true, + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureTemplateRBAC: 1, + }, + }, + }) + + templateAdmin, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleTemplateAdmin()) + user, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleMember()) + + version := coderdtest.CreateTemplateVersion(t, templateAdmin, owner.OrganizationID, nil) + coderdtest.AwaitTemplateVersionJobCompleted(t, templateAdmin, version.ID) + template := coderdtest.CreateTemplate(t, templateAdmin, owner.OrganizationID, version.ID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + // Remove everyone access + err := templateAdmin.UpdateTemplateACL(ctx, template.ID, codersdk.UpdateTemplateACL{ + UserPerms: map[string]codersdk.TemplateRole{}, + GroupPerms: map[string]codersdk.TemplateRole{ + owner.OrganizationID.String(): codersdk.TemplateRoleDeleted, + }, + }) + require.NoError(t, err) + + // Test "everyone" access is revoked to the regular user + _, err = user.Template(ctx, template.ID) + require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusNotFound, apiErr.StatusCode()) + + _, err = user.CreateUserWorkspace(ctx, codersdk.Me, codersdk.CreateWorkspaceRequest{ + TemplateID: template.ID, + Name: "random", + AutostartSchedule: ptr.Ref("CRON_TZ=US/Central 30 9 * * 1-5"), + TTLMillis: ptr.Ref((8 * time.Hour).Milliseconds()), + AutomaticUpdates: codersdk.AutomaticUpdatesNever, + }) + require.Error(t, err) + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) + require.Contains(t, apiErr.Message, "doesn't exist") + }) +} + +func TestCreateUserWorkspace(t *testing.T) { + t.Parallel() + + t.Run("NoTemplateAccess", func(t *testing.T) { + t.Parallel() + + dv := coderdtest.DeploymentValues(t) + dv.Experiments = []string{string(codersdk.ExperimentMultiOrganization)} + client, first := coderdenttest.New(t, &coderdenttest.Options{ + Options: &coderdtest.Options{ + DeploymentValues: dv, + }, + LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureTemplateRBAC: 1, + codersdk.FeatureMultipleOrganizations: 1, + }, + }, + }) + + other, _ := coderdtest.CreateAnotherUser(t, client, first.OrganizationID, rbac.RoleMember(), rbac.RoleOwner()) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + org, err := other.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{ + Name: "another", + }) + require.NoError(t, err) + version := coderdtest.CreateTemplateVersion(t, other, org.ID, nil) + template := coderdtest.CreateTemplate(t, other, org.ID, version.ID) + + _, err = client.CreateUserWorkspace(ctx, codersdk.Me, codersdk.CreateWorkspaceRequest{ + TemplateID: template.ID, + Name: "workspace", + }) + require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusNotAcceptable, apiErr.StatusCode()) + }) + + // Test that a user cannot indirectly access + // a template they do not have access to. + t.Run("Unauthorized", func(t *testing.T) { + t.Parallel() + + client, user := coderdenttest.New(t, &coderdenttest.Options{LicenseOptions: &coderdenttest.LicenseOptions{ + Features: license.Features{ + codersdk.FeatureTemplateRBAC: 1, + }, + }}) + templateAdminClient, _ := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleTemplateAdmin()) + + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + acl, err := templateAdminClient.TemplateACL(ctx, template.ID) + require.NoError(t, err) + + require.Len(t, acl.Groups, 1) + require.Len(t, acl.Users, 0) + + err = templateAdminClient.UpdateTemplateACL(ctx, template.ID, codersdk.UpdateTemplateACL{ + GroupPerms: map[string]codersdk.TemplateRole{ + acl.Groups[0].ID.String(): codersdk.TemplateRoleDeleted, + }, + }) + require.NoError(t, err) + + client1, user1 := coderdtest.CreateAnotherUser(t, client, user.OrganizationID) + + _, err = client1.Template(ctx, template.ID) + require.Error(t, err) + cerr, ok := codersdk.AsError(err) + require.True(t, ok) + require.Equal(t, http.StatusNotFound, cerr.StatusCode()) + + req := codersdk.CreateWorkspaceRequest{ + TemplateID: template.ID, + Name: "testme", + AutostartSchedule: ptr.Ref("CRON_TZ=US/Central 30 9 * * 1-5"), + TTLMillis: ptr.Ref((8 * time.Hour).Milliseconds()), + } + + _, err = client1.CreateUserWorkspace(ctx, user1.ID.String(), req) + require.Error(t, err) + }) } func TestWorkspaceAutobuild(t *testing.T) { @@ -176,7 +321,7 @@ func TestWorkspaceAutobuild(t *testing.T) { ctr.FailureTTLMillis = ptr.Ref[int64](failureTTL.Milliseconds()) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusFailed, build.Status) ticker <- build.Job.CompletedAt.Add(failureTTL * 2) @@ -222,7 +367,7 @@ func TestWorkspaceAutobuild(t *testing.T) { ctr.FailureTTLMillis = ptr.Ref[int64](failureTTL.Milliseconds()) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusFailed, build.Status) // Make it impossible to trigger the failure TTL. @@ -271,7 +416,7 @@ func TestWorkspaceAutobuild(t *testing.T) { require.Zero(t, template.TimeTilDormantAutoDeleteMillis) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) ticker <- time.Now() @@ -415,7 +560,7 @@ func TestWorkspaceAutobuild(t *testing.T) { workspaces := make([]codersdk.Workspace, 0, numWorkspaces) for i := 0; i < numWorkspaces; i++ { - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) workspaces = append(workspaces, ws) @@ -465,7 +610,7 @@ func TestWorkspaceAutobuild(t *testing.T) { ctr.TimeTilDormantMillis = ptr.Ref[int64](inactiveTTL.Milliseconds()) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) // Make it impossible to trigger the inactive ttl. @@ -508,7 +653,7 @@ func TestWorkspaceAutobuild(t *testing.T) { ctr.TimeTilDormantAutoDeleteMillis = ptr.Ref[int64](autoDeleteTTL.Milliseconds()) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Nil(t, ws.DormantAt) require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) @@ -552,7 +697,7 @@ func TestWorkspaceAutobuild(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + ws := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = nil }) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) @@ -608,7 +753,7 @@ func TestWorkspaceAutobuild(t *testing.T) { }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) @@ -678,7 +823,7 @@ func TestWorkspaceAutobuild(t *testing.T) { ctr.TimeTilDormantAutoDeleteMillis = ptr.Ref[int64](dormantTTL.Milliseconds()) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - ws := coderdtest.CreateWorkspace(t, anotherClient, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, anotherClient, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, anotherClient, ws.LatestBuild.ID) require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) @@ -745,7 +890,7 @@ func TestWorkspaceAutobuild(t *testing.T) { sched, err := cron.Weekly("CRON_TZ=UTC 0 * * * *") require.NoError(t, err) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + ws := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = ptr.Ref(sched.String()) }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) @@ -824,7 +969,7 @@ func TestWorkspaceAutobuild(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - ws := coderdtest.CreateWorkspace(t, templateAdmin, user.OrganizationID, template.ID) + ws := coderdtest.CreateWorkspace(t, templateAdmin, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, templateAdmin, ws.LatestBuild.ID) // Create a new version that will fail when we try to delete a workspace. @@ -909,7 +1054,7 @@ func TestWorkspaceAutobuild(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version1.ID) require.Equal(t, version1.ID, template.ActiveVersionID) - ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + ws := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = ptr.Ref(sched.String()) }) @@ -987,7 +1132,7 @@ func TestTemplateDoesNotAllowUserAutostop(t *testing.T) { ctr.AllowUserAutostop = ptr.Ref(false) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace := coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.TTLMillis = nil // ensure that no default TTL is set }) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) @@ -1024,7 +1169,7 @@ func TestTemplateDoesNotAllowUserAutostop(t *testing.T) { ctr.AllowUserAutostop = ptr.Ref(false) }) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) require.Equal(t, false, template.AllowUserAutostop, "template should have AllowUserAutostop as false") @@ -1081,7 +1226,7 @@ func TestExecutorAutostartBlocked(t *testing.T) { } }) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace = coderdtest.CreateWorkspace(t, client, owner.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + workspace = coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.AutostartSchedule = ptr.Ref(sched.String()) }) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) @@ -1183,7 +1328,7 @@ func TestWorkspacesWithoutTemplatePerms(t *testing.T) { template := coderdtest.CreateTemplate(t, client, first.OrganizationID, version.ID) user, _ := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) - workspace := coderdtest.CreateWorkspace(t, user, first.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, user, template.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() @@ -1211,7 +1356,7 @@ func TestWorkspacesWithoutTemplatePerms(t *testing.T) { version2 := coderdtest.CreateTemplateVersion(t, client, first.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version2.ID) template2 := coderdtest.CreateTemplate(t, client, first.OrganizationID, version2.ID) - _ = coderdtest.CreateWorkspace(t, user, first.OrganizationID, template2.ID) + _ = coderdtest.CreateWorkspace(t, user, template2.ID) workspaces, err := user.Workspaces(ctx, codersdk.WorkspaceFilter{}) require.NoError(t, err, "fetch workspaces should not fail") @@ -1245,7 +1390,7 @@ func TestWorkspaceLock(t *testing.T) { ctr.TimeTilDormantAutoDeleteMillis = ptr.Ref[int64](dormantTTL.Milliseconds()) }) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -1357,7 +1502,7 @@ func TestAdminViewAllWorkspaces(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) diff --git a/enterprise/wsproxy/wsproxy_test.go b/enterprise/wsproxy/wsproxy_test.go index f49f4074dc7ba..430807a60ae67 100644 --- a/enterprise/wsproxy/wsproxy_test.go +++ b/enterprise/wsproxy/wsproxy_test.go @@ -179,7 +179,7 @@ func TestDERP(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) workspace.LatestBuild = build @@ -418,7 +418,7 @@ func TestDERPEndToEnd(t *testing.T) { }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) build := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) workspace.LatestBuild = build diff --git a/scaletest/agentconn/run_test.go b/scaletest/agentconn/run_test.go index 1ce4dc1e5d015..2b05c0c302b00 100644 --- a/scaletest/agentconn/run_test.go +++ b/scaletest/agentconn/run_test.go @@ -253,7 +253,7 @@ func setupRunnerTest(t *testing.T) (client *codersdk.Client, agentID uuid.UUID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) _ = agenttest.New(t, client.URL, authToken) diff --git a/scaletest/reconnectingpty/run_test.go b/scaletest/reconnectingpty/run_test.go index c740f922fa432..817fabd1c5373 100644 --- a/scaletest/reconnectingpty/run_test.go +++ b/scaletest/reconnectingpty/run_test.go @@ -274,7 +274,7 @@ func setupRunnerTest(t *testing.T) (client *codersdk.Client, agentID uuid.UUID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) _ = agenttest.New(t, client.URL, authToken) diff --git a/scaletest/workspacetraffic/run_test.go b/scaletest/workspacetraffic/run_test.go index 4e54c45da4bbf..bb9d88b969d58 100644 --- a/scaletest/workspacetraffic/run_test.go +++ b/scaletest/workspacetraffic/run_test.go @@ -71,7 +71,7 @@ func TestRun(t *testing.T) { template = coderdtest.CreateTemplate(t, client, firstUser.OrganizationID, version.ID) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) // In order to be picked up as a scaletest workspace, the workspace must be named specifically - ws = coderdtest.CreateWorkspace(t, client, firstUser.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + ws = coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.Name = "scaletest-test" }) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) @@ -190,7 +190,7 @@ func TestRun(t *testing.T) { template = coderdtest.CreateTemplate(t, client, firstUser.OrganizationID, version.ID) _ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) // In order to be picked up as a scaletest workspace, the workspace must be named specifically - ws = coderdtest.CreateWorkspace(t, client, firstUser.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + ws = coderdtest.CreateWorkspace(t, client, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.Name = "scaletest-test" }) _ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) diff --git a/site/src/api/api.ts b/site/src/api/api.ts index ca006a3a16997..a98ce16afc61b 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -1019,12 +1019,11 @@ class ApiMethods { }; createWorkspace = async ( - organizationId: string, userId = "me", workspace: TypesGen.CreateWorkspaceRequest, ): Promise => { const response = await this.axios.post( - `/api/v2/organizations/${organizationId}/members/${userId}/workspaces`, + `/api/v2/users/${userId}/workspaces`, workspace, ); diff --git a/site/src/api/queries/templates.ts b/site/src/api/queries/templates.ts index 2d0485b8f347b..605ef54e0b35b 100644 --- a/site/src/api/queries/templates.ts +++ b/site/src/api/queries/templates.ts @@ -13,20 +13,20 @@ import type { import { delay } from "utils/delay"; import { getTemplateVersionFiles } from "utils/templateVersion"; -export const templateByNameKey = (organizationId: string, name: string) => [ - organizationId, +export const templateByNameKey = (organization: string, name: string) => [ + organization, "template", name, "settings", ]; export const templateByName = ( - organizationId: string, + organization: string, name: string, ): QueryOptions