-
Notifications
You must be signed in to change notification settings - Fork 979
feat!: add ability to cancel pending workspace build #18713
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
Changes from 1 commit
ba41ae8
c4ee5b6
c49c33e
ba1dbf3
acffda6
b672d76
86a34df
42170ab
5db9d71
1ede20c
2597615
6c2d0cf
c800494
c5cb203
1de84cc
17fb6a3
1b7b614
634f556
4deace0
43430fa
6272d93
4d4a01d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -596,56 +596,58 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques | |||||
return | ||||||
} | ||||||
|
||||||
code := http.StatusOK | ||||||
resp := codersdk.Response{} | ||||||
err = api.Database.InTx(func(store database.Store) error { | ||||||
valid, err := api.verifyUserCanCancelWorkspaceBuilds(ctx, store, httpmw.APIKey(r).UserID, workspace.TemplateID) | ||||||
valid, err := verifyUserCanCancelWorkspaceBuilds(ctx, store, httpmw.APIKey(r).UserID, workspace.TemplateID) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We often just use the variable name |
||||||
if err != nil { | ||||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ | ||||||
Message: "Internal error verifying permission to cancel workspace build.", | ||||||
Detail: err.Error(), | ||||||
}) | ||||||
return nil | ||||||
code = http.StatusInternalServerError | ||||||
resp.Message = "Internal error verifying permission to cancel workspace build." | ||||||
resp.Detail = err.Error() | ||||||
|
||||||
return xerrors.Errorf("verify user can cancel workspace builds: %w", err) | ||||||
} | ||||||
if !valid { | ||||||
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{ | ||||||
Message: "User is not allowed to cancel workspace builds. Owner role is required.", | ||||||
}) | ||||||
return nil | ||||||
code = http.StatusForbidden | ||||||
resp.Message = "User is not allowed to cancel workspace builds. Owner role is required." | ||||||
|
||||||
return xerrors.Errorf("user is not allowed to cancel workspace builds") | ||||||
} | ||||||
|
||||||
job, err := store.GetProvisionerJobByID(ctx, workspaceBuild.JobID) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably be a clone of this query with a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, I forgot to change that query 🙅 |
||||||
if err != nil { | ||||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ | ||||||
Message: "Internal error fetching provisioner job.", | ||||||
Detail: err.Error(), | ||||||
}) | ||||||
return nil | ||||||
code = http.StatusInternalServerError | ||||||
resp.Message = "Internal error fetching provisioner job." | ||||||
resp.Detail = err.Error() | ||||||
|
||||||
return xerrors.Errorf("get provisioner job: %w", err) | ||||||
} | ||||||
if job.CompletedAt.Valid { | ||||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ | ||||||
Message: "Job has already completed!", | ||||||
}) | ||||||
return nil | ||||||
code = http.StatusBadRequest | ||||||
resp.Message = "Job has already completed!" | ||||||
|
||||||
return xerrors.Errorf("job has already completed") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
if job.CanceledAt.Valid { | ||||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ | ||||||
Message: "Job has already been marked as canceled!", | ||||||
}) | ||||||
return nil | ||||||
code = http.StatusBadRequest | ||||||
resp.Message = "Job has already been marked as canceled!" | ||||||
|
||||||
return xerrors.Errorf("job has already been marked as canceled") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
if expectStatus != "" { | ||||||
if expectStatus != "running" && expectStatus != "pending" { | ||||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ | ||||||
Message: "Invalid expect_status. Only 'running' or 'pending' are allowed.", | ||||||
}) | ||||||
return nil | ||||||
code = http.StatusBadRequest | ||||||
resp.Message = "Invalid expect_status. Only 'running' or 'pending' are allowed." | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
return xerrors.Errorf("invalid expect_status") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
if job.JobStatus != database.ProvisionerJobStatus(expectStatus) { | ||||||
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{ | ||||||
Message: "Job is not in the expected state.", | ||||||
}) | ||||||
return nil | ||||||
code = http.StatusPreconditionFailed | ||||||
resp.Message = "Job is not in the expected state." | ||||||
|
||||||
return xerrors.Errorf("job is not in the expected state") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
} | ||||||
|
||||||
|
@@ -662,20 +664,17 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques | |||||
}, | ||||||
}) | ||||||
if err != nil { | ||||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ | ||||||
Message: "Internal error updating provisioner job.", | ||||||
Detail: err.Error(), | ||||||
}) | ||||||
return nil | ||||||
code = http.StatusInternalServerError | ||||||
resp.Message = "Internal error updating provisioner job." | ||||||
resp.Detail = err.Error() | ||||||
|
||||||
return xerrors.Errorf("update provisioner job: %w", err) | ||||||
} | ||||||
|
||||||
return nil | ||||||
}, nil) | ||||||
if err != nil { | ||||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ | ||||||
Message: "Internal error updating provisioner job.", | ||||||
Detail: err.Error(), | ||||||
}) | ||||||
httpapi.Write(ctx, rw, code, resp) | ||||||
deansheather marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
return | ||||||
} | ||||||
|
||||||
|
@@ -689,7 +688,7 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques | |||||
}) | ||||||
} | ||||||
|
||||||
func (*API) verifyUserCanCancelWorkspaceBuilds(ctx context.Context, store database.Store, userID uuid.UUID, templateID uuid.UUID) (bool, error) { | ||||||
func verifyUserCanCancelWorkspaceBuilds(ctx context.Context, store database.Store, userID uuid.UUID, templateID uuid.UUID) (bool, error) { | ||||||
template, err := store.GetTemplateByID(ctx, templateID) | ||||||
if err != nil { | ||||||
return false, xerrors.New("no template exists for this workspace") | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably have a default status code of 500 and a generic error message, otherwise if the tx returns an error below (because the tx couldn't start) you'll be returning an empty 200 response.