Skip to content

fix: add some missing workspace updates #7790

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 3 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Add some missing workspace updates
There are some failure cases where we do not set the type as a workspace
build which causes the workspace update to never be published.
  • Loading branch information
code-asher committed Jul 14, 2023
commit 7b1f5f9e7b9f24c43157daecc9c8718794f845fc
4 changes: 4 additions & 0 deletions coderd/coderdtest/coderdtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,10 +643,14 @@ func CreateWorkspaceBuild(
client *codersdk.Client,
workspace codersdk.Workspace,
transition database.WorkspaceTransition,
mutators ...func(*codersdk.CreateWorkspaceBuildRequest),
) codersdk.WorkspaceBuild {
req := codersdk.CreateWorkspaceBuildRequest{
Transition: codersdk.WorkspaceTransition(transition),
}
for _, mut := range mutators {
mut(&req)
}
build, err := client.CreateWorkspaceBuild(context.Background(), workspace.ID, req)
require.NoError(t, err)
return build
Expand Down
27 changes: 13 additions & 14 deletions coderd/provisionerdserver/provisionerdserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,31 +632,30 @@ func (server *Server) FailJob(ctx context.Context, failJob *proto.FailedJob) (*p

switch jobType := failJob.Type.(type) {
case *proto.FailedJob_WorkspaceBuild_:
if jobType.WorkspaceBuild.State == nil {
break
}
Comment on lines -635 to -637
Copy link
Member Author

@code-asher code-asher Jun 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what exactly this was guarding against (is there a danger to updating with empty state, maybe it would remove any previous state but that might be desired?) so maybe removing it has some unintended consequences...it fixes the unit test I added though. Seems not all workspace build failures include state.

Copy link
Member Author

@code-asher code-asher Jun 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it back but only gated the update behind it since that appears specifically for updating the state and I suppose we might not want to do that when no state was included (still not sure though) but we still want the publish.

var input WorkspaceProvisionJob
err = json.Unmarshal(job.Input, &input)
if err != nil {
return nil, xerrors.Errorf("unmarshal workspace provision input: %w", err)
}

var build database.WorkspaceBuild
err := server.Database.InTx(func(db database.Store) error {
workspaceBuild, err := db.GetWorkspaceBuildByID(ctx, input.WorkspaceBuildID)
err = server.Database.InTx(func(db database.Store) error {
build, err = db.GetWorkspaceBuildByID(ctx, input.WorkspaceBuildID)
if err != nil {
return xerrors.Errorf("get workspace build: %w", err)
}

build, err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{
ID: input.WorkspaceBuildID,
UpdatedAt: database.Now(),
ProvisionerState: jobType.WorkspaceBuild.State,
Deadline: workspaceBuild.Deadline,
MaxDeadline: workspaceBuild.MaxDeadline,
})
if err != nil {
return xerrors.Errorf("update workspace build state: %w", err)
if jobType.WorkspaceBuild.State != nil {
_, err = db.UpdateWorkspaceBuildByID(ctx, database.UpdateWorkspaceBuildByIDParams{
ID: input.WorkspaceBuildID,
UpdatedAt: database.Now(),
ProvisionerState: jobType.WorkspaceBuild.State,
Deadline: build.Deadline,
MaxDeadline: build.MaxDeadline,
})
if err != nil {
return xerrors.Errorf("update workspace build state: %w", err)
}
}

return nil
Expand Down
30 changes: 27 additions & 3 deletions coderd/workspaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2037,6 +2037,7 @@ func TestWorkspaceExtend(t *testing.T) {
func TestWorkspaceWatcher(t *testing.T) {
t.Parallel()
client, closeFunc := coderdtest.NewWithProvisionerCloser(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
defer closeFunc.Close()
user := coderdtest.CreateFirstUser(t, client)
authToken := uuid.NewString()
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Expand Down Expand Up @@ -2120,7 +2121,6 @@ func TestWorkspaceWatcher(t *testing.T) {
return w.LatestBuild.Resources[0].Agents[0].Status == codersdk.WorkspaceAgentDisconnected
})

closeFunc.Close()
build := coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStart)
wait("first is for the workspace build itself", nil)
err = client.CancelWorkspaceBuild(ctx, build.ID)
Expand All @@ -2133,13 +2133,37 @@ func TestWorkspaceWatcher(t *testing.T) {
require.NoError(t, err)
wait("update workspace name", nil)

// Add a new version that will fail.
updatedVersion := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionPlan: echo.ProvisionComplete,
ProvisionApply: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{
Error: "test error",
},
},
}},
}, func(req *codersdk.CreateTemplateVersionRequest) {
req.TemplateID = template.ID
})
coderdtest.AwaitTemplateVersionJob(t, client, updatedVersion.ID)
err = client.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{
ID: template.ActiveVersionID,
ID: updatedVersion.ID,
})
require.NoError(t, err)
wait("update active template version", nil)

cancel()
// Build with the new template; should end up with a failure state.
_ = coderdtest.CreateWorkspaceBuild(t, client, workspace, database.WorkspaceTransitionStart, func(req *codersdk.CreateWorkspaceBuildRequest) {
req.TemplateVersionID = updatedVersion.ID
})
wait("workspace build pending", func(w codersdk.Workspace) bool {
return w.LatestBuild.Status == codersdk.WorkspaceStatusPending
})
wait("workspace build failed", func(w codersdk.Workspace) bool {
return w.LatestBuild.Status == codersdk.WorkspaceStatusFailed
})
}

func mustLocation(t *testing.T, location string) *time.Location {
Expand Down
14 changes: 10 additions & 4 deletions provisionerd/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ func (r *Runner) buildWorkspace(ctx context.Context, stage string, req *sdkproto
// will still be available for us to send the cancel to the provisioner
stream, err := r.provisioner.Provision(ctx)
if err != nil {
return nil, r.failedJobf("provision: %s", err)
return nil, r.failedWorkspaceBuildf("provision: %s", err)
}
defer stream.Close()
go func() {
Expand All @@ -909,13 +909,13 @@ func (r *Runner) buildWorkspace(ctx context.Context, stage string, req *sdkproto

err = stream.Send(req)
if err != nil {
return nil, r.failedJobf("start provision: %s", err)
return nil, r.failedWorkspaceBuildf("start provision: %s", err)
}

for {
msg, err := stream.Recv()
if err != nil {
return nil, r.failedJobf("recv workspace provision: %s", err)
return nil, r.failedWorkspaceBuildf("recv workspace provision: %s", err)
}
switch msgType := msg.Type.(type) {
case *sdkproto.Provision_Response_Log:
Expand Down Expand Up @@ -958,7 +958,7 @@ func (r *Runner) buildWorkspace(ctx context.Context, stage string, req *sdkproto
// Stop looping!
return msgType.Complete, nil
default:
return nil, r.failedJobf("invalid message type %T received from provisioner", msg.Type)
return nil, r.failedWorkspaceBuildf("invalid message type %T received from provisioner", msg.Type)
}
}
}
Expand Down Expand Up @@ -1092,6 +1092,12 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p
}, nil
}

func (r *Runner) failedWorkspaceBuildf(format string, args ...interface{}) *proto.FailedJob {
failedJob := r.failedJobf(format, args...)
failedJob.Type = &proto.FailedJob_WorkspaceBuild_{}
return failedJob
}

func (r *Runner) failedJobf(format string, args ...interface{}) *proto.FailedJob {
message := fmt.Sprintf(format, args...)
var code string
Expand Down