Skip to content

feat: Allow user to cancel workspace jobs #5115

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 19 commits into from
Nov 21, 2022
Prev Previous commit
Next Next commit
Logic: block cancelling
  • Loading branch information
mtojek committed Nov 18, 2022
commit ba443ebdb22856c1fb17345fa11c4783515b87be
37 changes: 37 additions & 0 deletions coderd/workspacebuilds.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import (
"github.com/coder/coder/codersdk"
)

var (
errTemplateNotExists = xerrors.New("No template exists for this workspace")
errUserNotExists = xerrors.New("User does not exist")
)

func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
workspaceBuild := httpmw.WorkspaceBuildParam(r)
Expand Down Expand Up @@ -599,6 +604,21 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques
return
}

valid, err := api.verifyUserCanCancelWorkspaceBuilds(ctx, httpmw.APIKey(r).UserID, workspace.TemplateID)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Copy link
Member

Choose a reason for hiding this comment

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

Suggestion: Both errors returned by verify seem like known states and caused by a user doing a nonsense request (vs. server making a mistake), maybe unauthorized would be a good response?

Copy link
Member Author

Choose a reason for hiding this comment

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

Unauthorized might be misleading while debugging potential customer issues. In theory, we don't expect an invalid user or an invalid template, and it doesn't look possible that the user passes it, hence an internal error.

Copy link
Member

Choose a reason for hiding this comment

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

Good points. After a second look I agree, didn't look closely enough at the inputs at first. 👍🏻

Message: "Internal error verifying permission to cancel workspace build.",
Detail: err.Error(),
})
return
}
if !valid {
httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
Message: "User is not allowed cancel workspace builds. Owner role is required.",
})
return
}

job, err := api.Database.GetProvisionerJobByID(ctx, workspaceBuild.JobID)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Expand Down Expand Up @@ -646,6 +666,23 @@ func (api *API) patchCancelWorkspaceBuild(rw http.ResponseWriter, r *http.Reques
})
}

func (api *API) verifyUserCanCancelWorkspaceBuilds(ctx context.Context, userID uuid.UUID, templateID uuid.UUID) (bool, error) {
template, err := api.Database.GetTemplateByID(ctx, templateID)
if err != nil {
return false, errTemplateNotExists
}

if template.AllowUserCancelWorkspaceJobs {
return true, nil // all users can cancel workspace builds
}

user, err := api.Database.GetUserByID(ctx, userID)
if err != nil {
return false, errUserNotExists
}
return slices.Contains(user.RBACRoles, rbac.RoleOwner()), nil // only user with "owner" role can cancel workspace builds
}

func (api *API) workspaceBuildResources(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
workspaceBuild := httpmw.WorkspaceBuildParam(r)
Expand Down