Skip to content

fix: coderd: putExtendWorkspace: move error from validation to message #3289

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 5 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
31 changes: 22 additions & 9 deletions coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ import (

const workspaceDefaultTTL = 2 * time.Hour

var (
ttlMin = time.Minute //nolint:revive // min here means 'minimum' not 'minutes'
ttlMax = 7 * 24 * time.Hour

errTTLMin = xerrors.New("time until shutdown must be at least one minute")
errTTLMax = xerrors.New("time until shutdown must be less than 7 days")
errDeadlineTooSoon = xerrors.New("new deadline must be at least 30 minutes in the future")
errDeadlineBeforeStart = xerrors.New("new deadline must be before workspace start time")
errDeadlineOverTemplateMax = xerrors.New("new deadline is greater than template allows")
)

func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
workspace := httpmw.WorkspaceParam(r)
if !api.Authorize(r, rbac.ActionRead, workspace) {
Expand Down Expand Up @@ -623,9 +634,11 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) {

newDeadline := req.Deadline.UTC()
if err := validWorkspaceDeadline(job.CompletedAt.Time, newDeadline, time.Duration(template.MaxTtl)); err != nil {
// NOTE(Cian): Putting the error in the Message field on request from the FE folks.
// Normally, we would put the validation error in Validations, but this endpoint is
// not tied to a form or specific named user input on the FE.
code = http.StatusBadRequest
resp.Message = "Bad extend workspace request."
resp.Validations = append(resp.Validations, codersdk.ValidationError{Field: "deadline", Detail: err.Error()})
resp.Message = "Cannot extend workspace: " + err.Error()
return err
}

Expand Down Expand Up @@ -894,12 +907,12 @@ func validWorkspaceTTLMillis(millis *int64, max time.Duration) (sql.NullInt64, e

dur := time.Duration(*millis) * time.Millisecond
truncated := dur.Truncate(time.Minute)
if truncated < time.Minute {
return sql.NullInt64{}, xerrors.New("time until shutdown must be at least one minute")
if truncated < ttlMin {
return sql.NullInt64{}, errTTLMin
}

if truncated > 24*7*time.Hour {
return sql.NullInt64{}, xerrors.New("time until shutdown must be less than 7 days")
if truncated > ttlMax {
return sql.NullInt64{}, errTTLMax
}

if truncated > max {
Expand All @@ -915,17 +928,17 @@ func validWorkspaceTTLMillis(millis *int64, max time.Duration) (sql.NullInt64, e
func validWorkspaceDeadline(startedAt, newDeadline time.Time, max time.Duration) error {
soon := time.Now().Add(29 * time.Minute)
if newDeadline.Before(soon) {
return xerrors.New("new deadline must be at least 30 minutes in the future")
return errDeadlineTooSoon
}

// No idea how this could happen.
if newDeadline.Before(startedAt) {
return xerrors.Errorf("new deadline must be before workspace start time")
return errDeadlineBeforeStart
}

delta := newDeadline.Sub(startedAt)
if delta > max {
return xerrors.New("new deadline is greater than template allows")
return errDeadlineOverTemplateMax
}

return nil
Expand Down
5 changes: 3 additions & 2 deletions coderd/workspaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1063,14 +1063,15 @@ func TestWorkspaceExtend(t *testing.T) {
err = client.PutExtendWorkspace(ctx, workspace.ID, codersdk.PutExtendWorkspaceRequest{
Deadline: deadlineTooSoon,
})
require.ErrorContains(t, err, "new deadline must be at least 30 minutes in the future", "setting a deadline less than 30 minutes in the future should fail")
require.ErrorContains(t, err, "unexpected status code 400: Cannot extend workspace: new deadline must be at least 30 minutes in the future", "setting a deadline less than 30 minutes in the future should fail")

// And with a deadline greater than the template max_ttl should also fail
deadlineExceedsMaxTTL := time.Now().Add(time.Duration(template.MaxTTLMillis) * time.Millisecond).Add(time.Minute)
err = client.PutExtendWorkspace(ctx, workspace.ID, codersdk.PutExtendWorkspaceRequest{
Deadline: deadlineExceedsMaxTTL,
})
require.ErrorContains(t, err, "new deadline is greater than template allows", "setting a deadline greater than that allowed by the template should fail")

require.ErrorContains(t, err, "unexpected status code 400: Cannot extend workspace: new deadline is greater than template allows", "setting a deadline greater than that allowed by the template should fail")

// Updating with a deadline 30 minutes in the future should succeed
deadlineJustSoonEnough := time.Now().Add(30 * time.Minute)
Expand Down