Skip to content

feat: add startup script logs to the ui #6558

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
99d510c
Add startup script logs to the database
code-asher Feb 23, 2023
66c8ec3
Add coderd endpoints for startup script logs
code-asher Feb 23, 2023
1cc3e9d
Push startup script logs from agent
code-asher Feb 23, 2023
45d250f
Pull startup script logs on frontend
code-asher Feb 23, 2023
7fed360
Merge branch 'main' into startuplogs
kylecarbs Mar 10, 2023
7ce73aa
Rename queries
kylecarbs Mar 10, 2023
b86c400
Add constraint
kylecarbs Mar 11, 2023
0c4d2c3
Start creating log sending loop
kylecarbs Mar 13, 2023
1bb700f
Add log sending to the agent
kylecarbs Mar 13, 2023
736705f
Add tests for streaming logs
kylecarbs Mar 13, 2023
f741523
Shorten notify channel name
kylecarbs Mar 14, 2023
54c30be
Add FE
kylecarbs Mar 14, 2023
adb06ea
Improve bulk log performance
kylecarbs Mar 15, 2023
4061b13
Finish UI display
kylecarbs Mar 15, 2023
4c5b630
Fix startup log visibility
kylecarbs Mar 15, 2023
05d536c
Add warning for overflow
kylecarbs Mar 16, 2023
34fde1a
Fix agent queue logs overflow
kylecarbs Mar 17, 2023
379f1f4
Display staartup logs in a virtual DOM for performance
kylecarbs Mar 19, 2023
decde5c
Fix agent queue with loads of logs
kylecarbs Mar 20, 2023
d74457c
Merge branch 'main' into startuplogs
kylecarbs Mar 20, 2023
ac55f48
Fix authorize test
kylecarbs Mar 20, 2023
8d75963
Remove faulty test
kylecarbs Mar 20, 2023
cc715cd
Fix startup and shutdown reporting error
kylecarbs Mar 20, 2023
e3a4b2c
Fix gen
kylecarbs Mar 20, 2023
399dad7
Merge branch 'main' into startuplogs
kylecarbs Mar 22, 2023
45c0aca
Fix comments
kylecarbs Mar 22, 2023
5a0b15d
Periodically purge old database entries
kylecarbs Mar 23, 2023
b1b3fcb
Add test fixture for migration
kylecarbs Mar 23, 2023
6e1032c
Add Storybook
kylecarbs Mar 23, 2023
3762e8d
Check if there are logs when displaying features
kylecarbs Mar 23, 2023
f6b9fce
Fix startup component overflow gap
kylecarbs Mar 23, 2023
c48658c
Fix startup log wrapping
kylecarbs Mar 23, 2023
4ec1a0e
Merge branch 'main' into startuplogs
kylecarbs Mar 23, 2023
b55b7a1
Merge branch 'main' into startuplogs
kylecarbs Mar 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename queries
  • Loading branch information
kylecarbs committed Mar 10, 2023
commit 7ce73aaf87fed7c27163921982c84efd0717cb09
2 changes: 1 addition & 1 deletion agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ type Client interface {
PostLifecycle(ctx context.Context, state agentsdk.PostLifecycleRequest) error
PostAppHealth(ctx context.Context, req agentsdk.PostAppHealthsRequest) error
PostStartup(ctx context.Context, req agentsdk.PostStartupRequest) error
InsertOrUpdateStartupLogs(ctx context.Context, req agentsdk.InsertOrUpdateStartupLogsRequest) error
AppendStartupLogs(ctx context.Context, req []agentsdk.StartupLog) error
}

func New(options Options) io.Closer {
Expand Down
2 changes: 1 addition & 1 deletion coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ func New(options *Options) *API {
r.Get("/metadata", api.workspaceAgentMetadata)
r.Route("/startup", func(r chi.Router) {
r.Post("/", api.postWorkspaceAgentStartup)
r.Patch("/logs", api.insertOrUpdateStartupScriptLogs)
r.Patch("/logs", api.patchWorkspaceAgentStartupLogs)
})
r.Post("/app-health", api.postWorkspaceAppHealth)
r.Get("/gitauth", api.workspaceAgentsGitAuth)
Expand Down
29 changes: 8 additions & 21 deletions coderd/database/dbauthz/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,14 @@ func (q *querier) GetProvisionerLogsByIDBetween(ctx context.Context, arg databas
return q.db.GetProvisionerLogsByIDBetween(ctx, arg)
}

func (q *querier) GetWorkspaceAgentStartupLogsBetween(ctx context.Context, arg database.GetWorkspaceAgentStartupLogsBetweenParams) ([]database.WorkspaceAgentStartupLog, error) {
_, err := q.GetWorkspaceAgentByID(ctx, arg.AgentID)
if err != nil {
return nil, err
}
return q.db.GetWorkspaceAgentStartupLogsBetween(ctx, arg)
}

func (q *querier) GetLicenses(ctx context.Context) ([]database.License, error) {
fetch := func(ctx context.Context, _ interface{}) ([]database.License, error) {
return q.db.GetLicenses(ctx)
Expand Down Expand Up @@ -1247,27 +1255,6 @@ func (q *querier) UpdateWorkspaceAgentStartupByID(ctx context.Context, arg datab
return q.db.UpdateWorkspaceAgentStartupByID(ctx, arg)
}

func (q *querier) GetStartupScriptLogsByJobID(ctx context.Context, jobID uuid.UUID) ([]database.StartupScriptLog, error) {
build, err := q.db.GetWorkspaceBuildByJobID(ctx, jobID)
if err != nil {
return nil, err
}
// Authorized fetch
_, err = q.GetWorkspaceByID(ctx, build.WorkspaceID)
if err != nil {
return nil, err
}
return q.db.GetStartupScriptLogsByJobID(ctx, jobID)
}

func (q *querier) InsertOrUpdateStartupScriptLog(ctx context.Context, arg database.InsertOrUpdateStartupScriptLogParams) error {
// Authorized fetch
if _, err := q.GetWorkspaceByAgentID(ctx, arg.AgentID); err != nil {
return err
}
return q.db.InsertOrUpdateStartupScriptLog(ctx, arg)
}

func (q *querier) GetWorkspaceAppByAgentIDAndSlug(ctx context.Context, arg database.GetWorkspaceAppByAgentIDAndSlugParams) (database.WorkspaceApp, error) {
// If we can fetch the workspace, we can fetch the apps. Use the authorized call.
if _, err := q.GetWorkspaceByAgentID(ctx, arg.AgentID); err != nil {
Expand Down
11 changes: 5 additions & 6 deletions coderd/database/dbauthz/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1004,20 +1004,19 @@ func (s *MethodTestSuite) TestWorkspace() {
ID: agt.ID,
}).Asserts(ws, rbac.ActionUpdate).Returns()
}))
s.Run("GetStartupScriptLogsByJobID", s.Subtest(func(db database.Store, check *expects) {
s.Run("GetWorkspaceAgentStartupLogsBetween", s.Subtest(func(db database.Store, check *expects) {
ws := dbgen.Workspace(s.T(), db, database.Workspace{})
build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()})
check.Args(build.JobID).Asserts(ws, rbac.ActionRead).Returns([]database.StartupScriptLog{})
check.Args(build.JobID).Asserts(ws, rbac.ActionRead).Returns([]database.WorkspaceAgentStartupLog{})
}))
s.Run("InsertOrUpdateStartupScriptLog", s.Subtest(func(db database.Store, check *expects) {
s.Run("InsertWorkspaceAgentStartupLogs", s.Subtest(func(db database.Store, check *expects) {
ws := dbgen.Workspace(s.T(), db, database.Workspace{})
build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()})
res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID})
agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID})
check.Args(database.InsertOrUpdateStartupScriptLogParams{
check.Args(database.InsertWorkspaceAgentStartupLogsParams{
AgentID: agt.ID,
JobID: build.JobID,
Output: "test",
Output: []string{"test"},
}).Asserts(ws, rbac.ActionUpdate).Returns()
}))
s.Run("GetWorkspaceAppByAgentIDAndSlug", s.Subtest(func(db database.Store, check *expects) {
Expand Down
4 changes: 4 additions & 0 deletions coderd/database/dbauthz/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ func (q *querier) InsertProvisionerJobLogs(ctx context.Context, arg database.Ins
return q.db.InsertProvisionerJobLogs(ctx, arg)
}

func (q *querier) InsertWorkspaceAgentStartupLogs(ctx context.Context, arg database.InsertWorkspaceAgentStartupLogsParams) ([]database.WorkspaceAgentStartupLog, error) {
return q.db.InsertWorkspaceAgentStartupLogs(ctx, arg)
}

func (q *querier) InsertProvisionerDaemon(ctx context.Context, arg database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) {
return q.db.InsertProvisionerDaemon(ctx, arg)
}
Expand Down
60 changes: 36 additions & 24 deletions coderd/database/dbfake/databasefake.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ func New() database.Store {
parameterSchemas: make([]database.ParameterSchema, 0),
parameterValues: make([]database.ParameterValue, 0),
provisionerDaemons: make([]database.ProvisionerDaemon, 0),
startupScriptLogs: make([]database.StartupScriptLog, 0),
workspaceAgents: make([]database.WorkspaceAgent, 0),
provisionerJobLogs: make([]database.ProvisionerJobLog, 0),
workspaceResources: make([]database.WorkspaceResource, 0),
Expand All @@ -61,6 +60,7 @@ func New() database.Store {
templateVersions: make([]database.TemplateVersion, 0),
templates: make([]database.Template, 0),
workspaceAgentStats: make([]database.WorkspaceAgentStat, 0),
workspaceAgentLogs: make([]database.WorkspaceAgentStartupLog, 0),
workspaceBuilds: make([]database.WorkspaceBuild, 0),
workspaceApps: make([]database.WorkspaceApp, 0),
workspaces: make([]database.Workspace, 0),
Expand Down Expand Up @@ -119,12 +119,12 @@ type data struct {
provisionerJobLogs []database.ProvisionerJobLog
provisionerJobs []database.ProvisionerJob
replicas []database.Replica
startupScriptLogs []database.StartupScriptLog
templateVersions []database.TemplateVersion
templateVersionParameters []database.TemplateVersionParameter
templateVersionVariables []database.TemplateVersionVariable
templates []database.Template
workspaceAgents []database.WorkspaceAgent
workspaceAgentLogs []database.WorkspaceAgentStartupLog
workspaceApps []database.WorkspaceApp
workspaceBuilds []database.WorkspaceBuild
workspaceBuildParameters []database.WorkspaceBuildParameter
Expand Down Expand Up @@ -3514,42 +3514,54 @@ func (q *fakeQuerier) UpdateWorkspaceAgentStartupByID(_ context.Context, arg dat
return sql.ErrNoRows
}

func (q *fakeQuerier) GetStartupScriptLogsByJobID(_ context.Context, jobID uuid.UUID) ([]database.StartupScriptLog, error) {
func (q *fakeQuerier) GetWorkspaceAgentStartupLogsBetween(ctx context.Context, arg database.GetWorkspaceAgentStartupLogsBetweenParams) ([]database.WorkspaceAgentStartupLog, error) {
if err := validateDatabaseType(arg); err != nil {
return nil, err
}

q.mutex.Lock()
defer q.mutex.Unlock()

logs := []database.StartupScriptLog{}
for _, log := range q.startupScriptLogs {
if log.JobID == jobID {
logs = append(logs, log)
logs := []database.WorkspaceAgentStartupLog{}
for _, log := range q.workspaceAgentLogs {
if log.AgentID != arg.AgentID {
continue
}
if arg.CreatedBefore != 0 && log.ID > arg.CreatedBefore {
continue
}
if arg.CreatedAfter != 0 && log.ID < arg.CreatedAfter {
continue
}
logs = append(logs, log)
}
return logs, sql.ErrNoRows
return logs, nil
}

func (q *fakeQuerier) InsertOrUpdateStartupScriptLog(_ context.Context, arg database.InsertOrUpdateStartupScriptLogParams) error {
func (q *fakeQuerier) InsertWorkspaceAgentStartupLogs(ctx context.Context, arg database.InsertWorkspaceAgentStartupLogsParams) ([]database.WorkspaceAgentStartupLog, error) {
if err := validateDatabaseType(arg); err != nil {
return err
return nil, err
}

q.mutex.Lock()
defer q.mutex.Unlock()

for index, log := range q.startupScriptLogs {
if log.JobID != arg.JobID {
continue
}

log.Output = arg.Output
q.startupScriptLogs[index] = log
return nil
logs := []database.WorkspaceAgentStartupLog{}
id := int64(1)
if len(q.workspaceAgentLogs) > 0 {
id = q.workspaceAgentLogs[len(q.workspaceAgentLogs)-1].ID
}
q.startupScriptLogs = append(q.startupScriptLogs, database.StartupScriptLog{
AgentID: arg.AgentID,
JobID: arg.JobID,
Output: arg.Output,
})
return nil
for index, output := range arg.Output {
id++
logs = append(logs, database.WorkspaceAgentStartupLog{
ID: id,
AgentID: arg.AgentID,
CreatedAt: arg.CreatedAt[index],
Output: output,
})
}
q.workspaceAgentLogs = append(q.workspaceAgentLogs, logs...)
return logs, nil
}

func (q *fakeQuerier) UpdateProvisionerJobByID(_ context.Context, arg database.UpdateProvisionerJobByIDParams) error {
Expand Down
30 changes: 15 additions & 15 deletions coderd/database/dump.sql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

6 changes: 0 additions & 6 deletions coderd/database/migrations/000100_add_startup_logs.up.sql

This file was deleted.

2 changes: 2 additions & 0 deletions coderd/database/migrations/000109_add_startup_logs.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DROP TABLE workspace_agent_startup_logs;
DROP INDEX workspace_agent_startup_logs_id_agent_id_idx;
9 changes: 9 additions & 0 deletions coderd/database/migrations/000109_add_startup_logs.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS workspace_agent_startup_logs (
agent_id uuid NOT NULL REFERENCES workspace_agents (id) ON DELETE CASCADE,
id bigint NOT NULL,
created_at timestamptz NOT NULL,
output varchar(1024) NOT NULL,
UNIQUE(agent_id, id)
);

CREATE INDEX workspace_agent_startup_logs_id_agent_id_idx ON workspace_agent_startup_logs USING btree (agent_id, id ASC);
13 changes: 7 additions & 6 deletions coderd/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading