feat: add exit code and status to workspace agent scripts (#24505)

For scripts that have not finished or in dry run cases these will be
omitted.
This commit is contained in:
Asher
2026-04-29 12:24:26 -08:00
committed by GitHub
parent 1c30d52b2b
commit be57af5ff0
25 changed files with 286 additions and 80 deletions
+28
View File
@@ -675,6 +675,27 @@ func WorkspaceAgentLog(log database.WorkspaceAgentLog) codersdk.WorkspaceAgentLo
}
}
func WorkspaceAgentScript(dbScript database.GetWorkspaceAgentScriptsByAgentIDsRow) codersdk.WorkspaceAgentScript {
script := codersdk.WorkspaceAgentScript{
ID: dbScript.ID,
LogPath: dbScript.LogPath,
LogSourceID: dbScript.LogSourceID,
Script: dbScript.Script,
Cron: dbScript.Cron,
RunOnStart: dbScript.RunOnStart,
RunOnStop: dbScript.RunOnStop,
StartBlocksLogin: dbScript.StartBlocksLogin,
Timeout: time.Duration(dbScript.TimeoutSeconds) * time.Second,
DisplayName: dbScript.DisplayName,
ExitCode: nullInt32Ptr(dbScript.ExitCode),
}
if dbScript.Status.Valid {
status := codersdk.WorkspaceAgentScriptStatus(dbScript.Status.WorkspaceAgentScriptTimingStatus)
script.Status = &status
}
return script
}
func ProvisionerDaemon(dbDaemon database.ProvisionerDaemon) codersdk.ProvisionerDaemon {
result := codersdk.ProvisionerDaemon{
ID: dbDaemon.ID,
@@ -1563,6 +1584,13 @@ func nullInt64Ptr(v sql.NullInt64) *int64 {
return &value
}
func nullInt32Ptr(n sql.NullInt32) *int32 {
if !n.Valid {
return nil
}
return &n.Int32
}
func nullStringPtr(v sql.NullString) *string {
if !v.Valid {
return nil
+1 -1
View File
@@ -4595,7 +4595,7 @@ func (q *querier) GetWorkspaceAgentScriptTimingsByBuildID(ctx context.Context, i
return q.db.GetWorkspaceAgentScriptTimingsByBuildID(ctx, id)
}
func (q *querier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceAgentScript, error) {
func (q *querier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]database.GetWorkspaceAgentScriptsByAgentIDsRow, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
return nil, err
}
+1 -1
View File
@@ -4694,7 +4694,7 @@ func (s *MethodTestSuite) TestSystemFunctions() {
}))
s.Run("GetWorkspaceAgentScriptsByAgentIDs", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
ids := []uuid.UUID{uuid.New()}
dbm.EXPECT().GetWorkspaceAgentScriptsByAgentIDs(gomock.Any(), ids).Return([]database.WorkspaceAgentScript{}, nil).AnyTimes()
dbm.EXPECT().GetWorkspaceAgentScriptsByAgentIDs(gomock.Any(), ids).Return([]database.GetWorkspaceAgentScriptsByAgentIDsRow{}, nil).AnyTimes()
check.Args(ids).Asserts(rbac.ResourceSystem, policy.ActionRead)
}))
s.Run("GetWorkspaceAgentLogSourcesByAgentIDs", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
+1 -1
View File
@@ -3024,7 +3024,7 @@ func (m queryMetricsStore) GetWorkspaceAgentScriptTimingsByBuildID(ctx context.C
return r0, r1
}
func (m queryMetricsStore) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceAgentScript, error) {
func (m queryMetricsStore) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]database.GetWorkspaceAgentScriptsByAgentIDsRow, error) {
start := time.Now()
r0, r1 := m.s.GetWorkspaceAgentScriptsByAgentIDs(ctx, ids)
m.queryLatencies.WithLabelValues("GetWorkspaceAgentScriptsByAgentIDs").Observe(time.Since(start).Seconds())
+2 -2
View File
@@ -5657,10 +5657,10 @@ func (mr *MockStoreMockRecorder) GetWorkspaceAgentScriptTimingsByBuildID(ctx, id
}
// GetWorkspaceAgentScriptsByAgentIDs mocks base method.
func (m *MockStore) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]database.WorkspaceAgentScript, error) {
func (m *MockStore) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]database.GetWorkspaceAgentScriptsByAgentIDsRow, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetWorkspaceAgentScriptsByAgentIDs", ctx, ids)
ret0, _ := ret[0].([]database.WorkspaceAgentScript)
ret0, _ := ret[0].([]database.GetWorkspaceAgentScriptsByAgentIDsRow)
ret1, _ := ret[1].(error)
return ret0, ret1
}
+1 -1
View File
@@ -732,7 +732,7 @@ type sqlcQuerier interface {
GetWorkspaceAgentMetadata(ctx context.Context, arg GetWorkspaceAgentMetadataParams) ([]WorkspaceAgentMetadatum, error)
GetWorkspaceAgentPortShare(ctx context.Context, arg GetWorkspaceAgentPortShareParams) (WorkspaceAgentPortShare, error)
GetWorkspaceAgentScriptTimingsByBuildID(ctx context.Context, id uuid.UUID) ([]GetWorkspaceAgentScriptTimingsByBuildIDRow, error)
GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgentScript, error)
GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]GetWorkspaceAgentScriptsByAgentIDsRow, error)
GetWorkspaceAgentStats(ctx context.Context, createdAt time.Time) ([]GetWorkspaceAgentStatsRow, error)
GetWorkspaceAgentStatsAndLabels(ctx context.Context, createdAt time.Time) ([]GetWorkspaceAgentStatsAndLabelsRow, error)
// `minute_buckets` could return 0 rows if there are no usage stats since `created_at`.
+32 -4
View File
@@ -33347,18 +33347,44 @@ func (q *sqlQuerier) UpdateWorkspacesTTLByTemplateID(ctx context.Context, arg Up
}
const getWorkspaceAgentScriptsByAgentIDs = `-- name: GetWorkspaceAgentScriptsByAgentIDs :many
SELECT workspace_agent_id, log_source_id, log_path, created_at, script, cron, start_blocks_login, run_on_start, run_on_stop, timeout_seconds, display_name, id FROM workspace_agent_scripts WHERE workspace_agent_id = ANY($1 :: uuid [ ])
SELECT
DISTINCT ON (workspace_agent_scripts.id) workspace_agent_scripts.workspace_agent_id, workspace_agent_scripts.log_source_id, workspace_agent_scripts.log_path, workspace_agent_scripts.created_at, workspace_agent_scripts.script, workspace_agent_scripts.cron, workspace_agent_scripts.start_blocks_login, workspace_agent_scripts.run_on_start, workspace_agent_scripts.run_on_stop, workspace_agent_scripts.timeout_seconds, workspace_agent_scripts.display_name, workspace_agent_scripts.id,
workspace_agent_script_timings.exit_code,
workspace_agent_script_timings.status
FROM workspace_agent_scripts
LEFT JOIN workspace_agent_script_timings
ON workspace_agent_script_timings.script_id = workspace_agent_scripts.id
WHERE workspace_agent_scripts.workspace_agent_id = ANY($1 :: uuid [ ])
ORDER BY workspace_agent_scripts.id, workspace_agent_script_timings.started_at
DESC NULLS LAST
`
func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgentScript, error) {
type GetWorkspaceAgentScriptsByAgentIDsRow struct {
WorkspaceAgentID uuid.UUID `db:"workspace_agent_id" json:"workspace_agent_id"`
LogSourceID uuid.UUID `db:"log_source_id" json:"log_source_id"`
LogPath string `db:"log_path" json:"log_path"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
Script string `db:"script" json:"script"`
Cron string `db:"cron" json:"cron"`
StartBlocksLogin bool `db:"start_blocks_login" json:"start_blocks_login"`
RunOnStart bool `db:"run_on_start" json:"run_on_start"`
RunOnStop bool `db:"run_on_stop" json:"run_on_stop"`
TimeoutSeconds int32 `db:"timeout_seconds" json:"timeout_seconds"`
DisplayName string `db:"display_name" json:"display_name"`
ID uuid.UUID `db:"id" json:"id"`
ExitCode sql.NullInt32 `db:"exit_code" json:"exit_code"`
Status NullWorkspaceAgentScriptTimingStatus `db:"status" json:"status"`
}
func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]GetWorkspaceAgentScriptsByAgentIDsRow, error) {
rows, err := q.db.QueryContext(ctx, getWorkspaceAgentScriptsByAgentIDs, pq.Array(ids))
if err != nil {
return nil, err
}
defer rows.Close()
var items []WorkspaceAgentScript
var items []GetWorkspaceAgentScriptsByAgentIDsRow
for rows.Next() {
var i WorkspaceAgentScript
var i GetWorkspaceAgentScriptsByAgentIDsRow
if err := rows.Scan(
&i.WorkspaceAgentID,
&i.LogSourceID,
@@ -33372,6 +33398,8 @@ func (q *sqlQuerier) GetWorkspaceAgentScriptsByAgentIDs(ctx context.Context, ids
&i.TimeoutSeconds,
&i.DisplayName,
&i.ID,
&i.ExitCode,
&i.Status,
); err != nil {
return nil, err
}
+10 -1
View File
@@ -17,4 +17,13 @@ SELECT
RETURNING workspace_agent_scripts.*;
-- name: GetWorkspaceAgentScriptsByAgentIDs :many
SELECT * FROM workspace_agent_scripts WHERE workspace_agent_id = ANY(@ids :: uuid [ ]);
SELECT
DISTINCT ON (workspace_agent_scripts.id) workspace_agent_scripts.*,
workspace_agent_script_timings.exit_code,
workspace_agent_script_timings.status
FROM workspace_agent_scripts
LEFT JOIN workspace_agent_script_timings
ON workspace_agent_script_timings.script_id = workspace_agent_scripts.id
WHERE workspace_agent_scripts.workspace_agent_id = ANY(@ids :: uuid [ ])
ORDER BY workspace_agent_scripts.id, workspace_agent_script_timings.started_at
DESC NULLS LAST;