From 752bcdc8b394b5c78344ce0e96deee0017b70aff Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 28 Aug 2023 14:17:00 +0000 Subject: [PATCH 1/2] fix(coderd): allow `workspaceAgentLogs` follow to return on non-latest-build --- coderd/workspaceagents.go | 25 ++++++++- coderd/workspaceagents_test.go | 98 ++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index c127b2342d4a3..fee75df08604b 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -23,6 +23,7 @@ import ( "github.com/go-chi/chi/v5" "github.com/google/uuid" "golang.org/x/exp/maps" + "golang.org/x/exp/slices" "golang.org/x/mod/semver" "golang.org/x/sync/errgroup" "golang.org/x/xerrors" @@ -481,6 +482,15 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) { return } + workspace, err := api.Database.GetWorkspaceByAgentID(ctx, workspaceAgent.ID) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching workspace by agent id.", + Detail: err.Error(), + }) + return + } + api.WebsocketWaitMutex.Lock() api.WebsocketWaitGroup.Add(1) api.WebsocketWaitMutex.Unlock() @@ -556,7 +566,8 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) { go func() { defer close(bufferedLogs) - for { + keepGoing := true + for keepGoing { select { case <-ctx.Done(): return @@ -565,6 +576,18 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) { t.Reset(recheckInterval) } + agents, err := api.Database.GetWorkspaceAgentsInLatestBuildByWorkspaceID(ctx, workspace.ID) + if err != nil { + if xerrors.Is(err, context.Canceled) { + return + } + logger.Warn(ctx, "failed to get workspace agents in latest build", slog.Error(err)) + continue + } + // If the agent is no longer in the latest build, we can stop after + // checking once. + keepGoing = slices.ContainsFunc(agents, func(agent database.WorkspaceAgent) bool { return agent.ID == workspaceAgent.ID }) + logs, err := api.Database.GetWorkspaceAgentLogsAfter(ctx, database.GetWorkspaceAgentLogsAfterParams{ AgentID: workspaceAgent.ID, CreatedAfter: lastSentLogID, diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 43694e95e67a9..54b74947746bc 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -242,6 +242,104 @@ func TestWorkspaceAgentStartupLogs(t *testing.T) { require.Equal(t, "testing", logChunk[0].Output) require.Equal(t, "testing2", logChunk[1].Output) }) + t.Run("Close logs on outdated build", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + client := coderdtest.New(t, &coderdtest.Options{ + IncludeProvisionerDaemon: true, + }) + user := coderdtest.CreateFirstUser(t, client) + authToken := uuid.NewString() + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ + Resources: []*proto.Resource{{ + Name: "example", + Type: "aws_instance", + Agents: []*proto.Agent{{ + Id: uuid.NewString(), + Auth: &proto.Agent_Token{ + Token: authToken, + }, + }}, + }}, + }, + }, + }}, + }) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + build := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + + agentClient := agentsdk.New(client.URL) + agentClient.SetSessionToken(authToken) + err := agentClient.PatchLogs(ctx, agentsdk.PatchLogs{ + Logs: []agentsdk.Log{ + { + CreatedAt: database.Now(), + Output: "testing", + }, + }, + }) + require.NoError(t, err) + + logs, closer, err := client.WorkspaceAgentLogsAfter(ctx, build.Resources[0].Agents[0].ID, 0, true) + require.NoError(t, err) + defer func() { + _ = closer.Close() + }() + + first := make(chan struct{}) + go func() { + select { + case <-ctx.Done(): + assert.Fail(t, "context done while waiting in goroutine") + case <-logs: + close(first) + } + }() + select { + case <-ctx.Done(): + require.FailNow(t, "context done while waiting for first log") + case <-first: + } + + // Create a new version and update the template. + version2, err := client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{ + TemplateID: template.ID, + Name: "version2", + StorageMethod: codersdk.ProvisionerStorageMethodFile, + FileID: version.Job.FileID, + Provisioner: codersdk.ProvisionerTypeEcho, + }) + require.NoError(t, err) + coderdtest.AwaitTemplateVersionJob(t, client, version2.ID) + + _ = coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStart, func(req *codersdk.CreateWorkspaceBuildRequest) { + req.TemplateVersionID = version2.ID + }) + + // Send a new log message to trigger a re-check. + err = agentClient.PatchLogs(ctx, agentsdk.PatchLogs{ + Logs: []agentsdk.Log{ + { + CreatedAt: database.Now(), + Output: "testing2", + }, + }, + }) + require.NoError(t, err) + + select { + case <-ctx.Done(): + require.FailNow(t, "context done while waiting for logs close") + case <-logs: + } + }) t.Run("PublishesOnOverflow", func(t *testing.T) { t.Parallel() ctx := testutil.Context(t, testutil.WaitMedium) From 671e482e5ac5a02587e4a0f875bccd2d6262a9ed Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 28 Aug 2023 14:26:55 +0000 Subject: [PATCH 2/2] skip the tpl version switch --- coderd/workspaceagents_test.go | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 54b74947746bc..2e51687afafa6 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -308,20 +308,7 @@ func TestWorkspaceAgentStartupLogs(t *testing.T) { case <-first: } - // Create a new version and update the template. - version2, err := client.CreateTemplateVersion(ctx, user.OrganizationID, codersdk.CreateTemplateVersionRequest{ - TemplateID: template.ID, - Name: "version2", - StorageMethod: codersdk.ProvisionerStorageMethodFile, - FileID: version.Job.FileID, - Provisioner: codersdk.ProvisionerTypeEcho, - }) - require.NoError(t, err) - coderdtest.AwaitTemplateVersionJob(t, client, version2.ID) - - _ = coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStart, func(req *codersdk.CreateWorkspaceBuildRequest) { - req.TemplateVersionID = version2.ID - }) + _ = coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStart) // Send a new log message to trigger a re-check. err = agentClient.PatchLogs(ctx, agentsdk.PatchLogs{ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy