feat(cli): add logs cmd (#21430)

This PR adds a command to view the provisioner and agent logs for a
given workspace.
Note: I did investigate using the existing `cliui` methods to tail the
logs but they are tailored to a very specific use-case.

Other changes:
- Adds `Agents` to `dbfake.WorkspaceResponse`
- Adds methods to generate provisioner and agent logs in `dbgen`

---------

Co-authored-by: Steven Masley <Emyrk@users.noreply.github.com>
This commit is contained in:
Cian Johnston
2026-01-08 09:58:10 +00:00
committed by GitHub
parent 49b34a716a
commit 0f446f99dd
10 changed files with 480 additions and 0 deletions
+3
View File
@@ -38,6 +38,7 @@ var ownerCtx = dbauthz.As(context.Background(), rbac.Subject{
type WorkspaceResponse struct {
Workspace database.WorkspaceTable
Build database.WorkspaceBuild
Agents []database.WorkspaceAgent
AgentToken string
TemplateVersionResponse
Task database.Task
@@ -189,6 +190,7 @@ func (b WorkspaceBuildBuilder) doInTX() WorkspaceResponse {
resp := WorkspaceResponse{
AgentToken: b.agentToken,
Agents: make([]database.WorkspaceAgent, 0),
}
if b.ws.TemplateID == uuid.Nil {
b.logger.Debug(context.Background(), "creating template and version")
@@ -422,6 +424,7 @@ func (b WorkspaceBuildBuilder) doInTX() WorkspaceResponse {
// Insert deleted subagent test antagonists for the workspace build.
// See also `dbgen.WorkspaceAgent()`.
for _, agent := range agents {
resp.Agents = append(resp.Agents, agent)
subAgent := dbgen.WorkspaceSubAgent(b.t, b.db, agent, database.WorkspaceAgent{
TroubleshootingURL: "I AM A TEST ANTAGONIST AND I AM HERE TO MESS UP YOUR TESTS. IF YOU SEE ME, SOMETHING IS WRONG AND SUB AGENT DELETION MAY NOT BE HANDLED CORRECTLY IN A QUERY.",
})
+28
View File
@@ -472,6 +472,20 @@ func WorkspaceAgentLogSource(t testing.TB, db database.Store, orig database.Work
return sources[0]
}
func WorkspaceAgentLog(t testing.TB, db database.Store, orig database.WorkspaceAgentLog) database.WorkspaceAgentLog {
log, err := db.InsertWorkspaceAgentLogs(genCtx, database.InsertWorkspaceAgentLogsParams{
AgentID: takeFirst(orig.AgentID, uuid.New()),
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
LogSourceID: takeFirst(orig.LogSourceID, uuid.New()),
OutputLength: int32(len(orig.Output)), // nolint: gosec // integer overflow is not a concern here
Level: []database.LogLevel{takeFirst(orig.Level, database.LogLevelInfo)},
Output: []string{takeFirst(orig.Output, "Test agent log")},
})
require.NoError(t, err, "insert workspace agent log")
require.Len(t, log, 1, "incorrect number of agent logs returned")
return log[0]
}
func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuild) database.WorkspaceBuild {
t.Helper()
@@ -863,6 +877,20 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
return job
}
func ProvisionerJobLog(t testing.TB, db database.Store, orig database.ProvisionerJobLog) database.ProvisionerJobLog {
logs, err := db.InsertProvisionerJobLogs(genCtx, database.InsertProvisionerJobLogsParams{
JobID: takeFirst(orig.JobID, uuid.New()),
CreatedAt: []time.Time{takeFirst(orig.CreatedAt, dbtime.Now())},
Source: []database.LogSource{takeFirst(orig.Source, database.LogSourceProvisioner)},
Level: []database.LogLevel{takeFirst(orig.Level, database.LogLevelInfo)},
Stage: []string{takeFirst(orig.Stage, "Test")},
Output: []string{takeFirst(orig.Output, "Provisioner job log")},
})
require.NoError(t, err, "insert provisioner job log")
require.Len(t, logs, 1, "insert provisioner job log returned incorrect number of logs")
return logs[0]
}
func ProvisionerKey(t testing.TB, db database.Store, orig database.ProvisionerKey) database.ProvisionerKey {
key, err := db.InsertProvisionerKey(genCtx, database.InsertProvisionerKeyParams{
ID: takeFirst(orig.ID, uuid.New()),