mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: extend workspace build reasons to track connection types (#18827)
This PR introduces new build reason values to identify what type of connection triggered a workspace build, helping to troubleshoot workspace-related issues. ## Database Migration Added migration 000349_extend_workspace_build_reason.up.sql that extends the build_reason enum with new values: ``` dashboard, cli, ssh_connection, vscode_connection, jetbrains_connection ``` ## Implementation The build reason is specified through the API when creating new workspace builds: - Dashboard: Automatically sets reason to `dashboard` when users start workspaces via the web interface - CLI `start` command: Sets reason to `cli` when workspaces are started via the command line - CLI `ssh` command: Sets reason to ssh_connection when workspaces are started due to SSH connections - VS Code connections: Will be set to `vscode_connection` by the VS Code extension through CLI hidden flag (https://github.com/coder/vscode-coder/pull/550) - JetBrains connections: Will be set to `jetbrains_connection` by the Jetbrains Toolbox (https://github.com/coder/coder-jetbrains-toolbox/pull/150) and Jetbrains Gateway extension (https://github.com/coder/jetbrains-coder/pull/561) ## UI Changes: * Tooltip with reason in Build history <img width="309" height="457" alt="image" src="https://github.com/user-attachments/assets/bde8440b-bf3b-49a1-a244-ed7e8eb9763c" /> * Reason in Audit Logs Row tooltip <img width="906" height="237" alt="image" src="https://github.com/user-attachments/assets/ebbb62c7-cf07-4398-afbf-323c83fb6426" /> <img width="909" height="188" alt="image" src="https://github.com/user-attachments/assets/1ddbab07-44bf-4dee-8867-b4e2cd56ae96" />
This commit is contained in:
Generated
+44
-2
@@ -11448,13 +11448,23 @@ const docTemplate = `{
|
||||
"initiator",
|
||||
"autostart",
|
||||
"autostop",
|
||||
"dormancy"
|
||||
"dormancy",
|
||||
"dashboard",
|
||||
"cli",
|
||||
"ssh_connection",
|
||||
"vscode_connection",
|
||||
"jetbrains_connection"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"BuildReasonInitiator",
|
||||
"BuildReasonAutostart",
|
||||
"BuildReasonAutostop",
|
||||
"BuildReasonDormancy"
|
||||
"BuildReasonDormancy",
|
||||
"BuildReasonDashboard",
|
||||
"BuildReasonCLI",
|
||||
"BuildReasonSSHConnection",
|
||||
"BuildReasonVSCodeConnection",
|
||||
"BuildReasonJetbrainsConnection"
|
||||
]
|
||||
},
|
||||
"codersdk.ChangePasswordWithOneTimePasscodeRequest": {
|
||||
@@ -12070,6 +12080,23 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.CreateWorkspaceBuildReason": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"dashboard",
|
||||
"cli",
|
||||
"ssh_connection",
|
||||
"vscode_connection",
|
||||
"jetbrains_connection"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"CreateWorkspaceBuildReasonDashboard",
|
||||
"CreateWorkspaceBuildReasonCLI",
|
||||
"CreateWorkspaceBuildReasonSSHConnection",
|
||||
"CreateWorkspaceBuildReasonVSCodeConnection",
|
||||
"CreateWorkspaceBuildReasonJetbrainsConnection"
|
||||
]
|
||||
},
|
||||
"codersdk.CreateWorkspaceBuildRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12094,6 +12121,21 @@ const docTemplate = `{
|
||||
"description": "Orphan may be set for the Destroy transition.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"reason": {
|
||||
"description": "Reason sets the reason for the workspace build.",
|
||||
"enum": [
|
||||
"dashboard",
|
||||
"cli",
|
||||
"ssh_connection",
|
||||
"vscode_connection",
|
||||
"jetbrains_connection"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.CreateWorkspaceBuildReason"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rich_parameter_values": {
|
||||
"description": "ParameterValues are optional. It will write params to the 'workspace' scope.\nThis will overwrite any existing parameters with the same name.\nThis will not delete old params not included in this list.",
|
||||
"type": "array",
|
||||
|
||||
Generated
+49
-2
@@ -10179,12 +10179,27 @@
|
||||
},
|
||||
"codersdk.BuildReason": {
|
||||
"type": "string",
|
||||
"enum": ["initiator", "autostart", "autostop", "dormancy"],
|
||||
"enum": [
|
||||
"initiator",
|
||||
"autostart",
|
||||
"autostop",
|
||||
"dormancy",
|
||||
"dashboard",
|
||||
"cli",
|
||||
"ssh_connection",
|
||||
"vscode_connection",
|
||||
"jetbrains_connection"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"BuildReasonInitiator",
|
||||
"BuildReasonAutostart",
|
||||
"BuildReasonAutostop",
|
||||
"BuildReasonDormancy"
|
||||
"BuildReasonDormancy",
|
||||
"BuildReasonDashboard",
|
||||
"BuildReasonCLI",
|
||||
"BuildReasonSSHConnection",
|
||||
"BuildReasonVSCodeConnection",
|
||||
"BuildReasonJetbrainsConnection"
|
||||
]
|
||||
},
|
||||
"codersdk.ChangePasswordWithOneTimePasscodeRequest": {
|
||||
@@ -10758,6 +10773,23 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.CreateWorkspaceBuildReason": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"dashboard",
|
||||
"cli",
|
||||
"ssh_connection",
|
||||
"vscode_connection",
|
||||
"jetbrains_connection"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"CreateWorkspaceBuildReasonDashboard",
|
||||
"CreateWorkspaceBuildReasonCLI",
|
||||
"CreateWorkspaceBuildReasonSSHConnection",
|
||||
"CreateWorkspaceBuildReasonVSCodeConnection",
|
||||
"CreateWorkspaceBuildReasonJetbrainsConnection"
|
||||
]
|
||||
},
|
||||
"codersdk.CreateWorkspaceBuildRequest": {
|
||||
"type": "object",
|
||||
"required": ["transition"],
|
||||
@@ -10778,6 +10810,21 @@
|
||||
"description": "Orphan may be set for the Destroy transition.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"reason": {
|
||||
"description": "Reason sets the reason for the workspace build.",
|
||||
"enum": [
|
||||
"dashboard",
|
||||
"cli",
|
||||
"ssh_connection",
|
||||
"vscode_connection",
|
||||
"jetbrains_connection"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.CreateWorkspaceBuildReason"
|
||||
}
|
||||
]
|
||||
},
|
||||
"rich_parameter_values": {
|
||||
"description": "ParameterValues are optional. It will write params to the 'workspace' scope.\nThis will overwrite any existing parameters with the same name.\nThis will not delete old params not included in this list.",
|
||||
"type": "array",
|
||||
|
||||
Generated
+6
-1
@@ -51,7 +51,12 @@ CREATE TYPE build_reason AS ENUM (
|
||||
'autostop',
|
||||
'dormancy',
|
||||
'failedstop',
|
||||
'autodelete'
|
||||
'autodelete',
|
||||
'dashboard',
|
||||
'cli',
|
||||
'ssh_connection',
|
||||
'vscode_connection',
|
||||
'jetbrains_connection'
|
||||
);
|
||||
|
||||
CREATE TYPE connection_status AS ENUM (
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
-- It's not possible to delete enum values.
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'dashboard';
|
||||
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'cli';
|
||||
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'ssh_connection';
|
||||
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'vscode_connection';
|
||||
ALTER TYPE build_reason ADD VALUE IF NOT EXISTS 'jetbrains_connection';
|
||||
@@ -349,12 +349,17 @@ func AllAutomaticUpdatesValues() []AutomaticUpdates {
|
||||
type BuildReason string
|
||||
|
||||
const (
|
||||
BuildReasonInitiator BuildReason = "initiator"
|
||||
BuildReasonAutostart BuildReason = "autostart"
|
||||
BuildReasonAutostop BuildReason = "autostop"
|
||||
BuildReasonDormancy BuildReason = "dormancy"
|
||||
BuildReasonFailedstop BuildReason = "failedstop"
|
||||
BuildReasonAutodelete BuildReason = "autodelete"
|
||||
BuildReasonInitiator BuildReason = "initiator"
|
||||
BuildReasonAutostart BuildReason = "autostart"
|
||||
BuildReasonAutostop BuildReason = "autostop"
|
||||
BuildReasonDormancy BuildReason = "dormancy"
|
||||
BuildReasonFailedstop BuildReason = "failedstop"
|
||||
BuildReasonAutodelete BuildReason = "autodelete"
|
||||
BuildReasonDashboard BuildReason = "dashboard"
|
||||
BuildReasonCli BuildReason = "cli"
|
||||
BuildReasonSshConnection BuildReason = "ssh_connection"
|
||||
BuildReasonVscodeConnection BuildReason = "vscode_connection"
|
||||
BuildReasonJetbrainsConnection BuildReason = "jetbrains_connection"
|
||||
)
|
||||
|
||||
func (e *BuildReason) Scan(src interface{}) error {
|
||||
@@ -399,7 +404,12 @@ func (e BuildReason) Valid() bool {
|
||||
BuildReasonAutostop,
|
||||
BuildReasonDormancy,
|
||||
BuildReasonFailedstop,
|
||||
BuildReasonAutodelete:
|
||||
BuildReasonAutodelete,
|
||||
BuildReasonDashboard,
|
||||
BuildReasonCli,
|
||||
BuildReasonSshConnection,
|
||||
BuildReasonVscodeConnection,
|
||||
BuildReasonJetbrainsConnection:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -413,6 +423,11 @@ func AllBuildReasonValues() []BuildReason {
|
||||
BuildReasonDormancy,
|
||||
BuildReasonFailedstop,
|
||||
BuildReasonAutodelete,
|
||||
BuildReasonDashboard,
|
||||
BuildReasonCli,
|
||||
BuildReasonSshConnection,
|
||||
BuildReasonVscodeConnection,
|
||||
BuildReasonJetbrainsConnection,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -329,13 +329,15 @@ func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Requ
|
||||
func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
apiKey := httpmw.APIKey(r)
|
||||
|
||||
workspace := httpmw.WorkspaceParam(r)
|
||||
var createBuild codersdk.CreateWorkspaceBuildRequest
|
||||
if !httpapi.Read(ctx, rw, r, &createBuild) {
|
||||
return
|
||||
}
|
||||
|
||||
builder := wsbuilder.New(workspace, database.WorkspaceTransition(createBuild.Transition), *api.BuildUsageChecker.Load()).
|
||||
transition := database.WorkspaceTransition(createBuild.Transition)
|
||||
builder := wsbuilder.New(workspace, transition, *api.BuildUsageChecker.Load()).
|
||||
Initiator(apiKey.UserID).
|
||||
RichParameterValues(createBuild.RichParameterValues).
|
||||
LogLevel(string(createBuild.LogLevel)).
|
||||
@@ -343,6 +345,10 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
||||
Experiments(api.Experiments).
|
||||
TemplateVersionPresetID(createBuild.TemplateVersionPresetID)
|
||||
|
||||
if transition == database.WorkspaceTransitionStart && createBuild.Reason != "" {
|
||||
builder = builder.Reason(database.BuildReason(createBuild.Reason))
|
||||
}
|
||||
|
||||
var (
|
||||
previousWorkspaceBuild database.WorkspaceBuild
|
||||
workspaceBuild *database.WorkspaceBuild
|
||||
|
||||
@@ -1808,6 +1808,30 @@ func TestPostWorkspaceBuild(t *testing.T) {
|
||||
assert.True(t, build.MatchedProvisioners.MostRecentlySeen.Valid)
|
||||
}
|
||||
})
|
||||
t.Run("WithReason", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client, closeDaemon := coderdtest.NewWithProvisionerCloser(t, &coderdtest.Options{
|
||||
IncludeProvisionerDaemon: true,
|
||||
})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
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, template.ID)
|
||||
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
|
||||
_ = closeDaemon.Close()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
|
||||
build, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||
TemplateVersionID: template.ActiveVersionID,
|
||||
Transition: codersdk.WorkspaceTransitionStart,
|
||||
Reason: codersdk.CreateWorkspaceBuildReasonDashboard,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, codersdk.BuildReasonDashboard, build.Reason)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWorkspaceBuildTimings(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user