From 8ab63aa3eb0be47137d6c849c074123c0a691b6f Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 1 Nov 2022 19:42:10 +0000 Subject: [PATCH 01/18] fix: remove unused min autostart feature --- cli/templateedit.go | 19 +++-- coderd/database/databasefake/databasefake.go | 30 ++++---- coderd/database/queries.sql.go | 50 ++++++------- coderd/database/queries/templates.sql | 8 +-- coderd/templates.go | 75 ++++++++------------ coderd/templates_test.go | 24 +++---- codersdk/templates.go | 9 ++- site/src/api/typesGenerated.ts | 1 - 8 files changed, 87 insertions(+), 129 deletions(-) diff --git a/cli/templateedit.go b/cli/templateedit.go index e0e4cf57a7196..09bdf5e069960 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -13,11 +13,10 @@ import ( func templateEdit() *cobra.Command { var ( - name string - description string - icon string - maxTTL time.Duration - minAutostartInterval time.Duration + name string + description string + icon string + maxTTL time.Duration ) cmd := &cobra.Command{ @@ -40,11 +39,10 @@ func templateEdit() *cobra.Command { // NOTE: coderd will ignore empty fields. req := codersdk.UpdateTemplateMeta{ - Name: name, - Description: description, - Icon: icon, - MaxTTLMillis: maxTTL.Milliseconds(), - MinAutostartIntervalMillis: minAutostartInterval.Milliseconds(), + Name: name, + Description: description, + Icon: icon, + MaxTTLMillis: maxTTL.Milliseconds(), } _, err = client.UpdateTemplateMeta(cmd.Context(), template.ID, req) @@ -60,7 +58,6 @@ func templateEdit() *cobra.Command { cmd.Flags().StringVarP(&description, "description", "", "", "Edit the template description") cmd.Flags().StringVarP(&icon, "icon", "", "", "Edit the template icon path") cmd.Flags().DurationVarP(&maxTTL, "max-ttl", "", 0, "Edit the template maximum time before shutdown - workspaces created from this template cannot stay running longer than this.") - cmd.Flags().DurationVarP(&minAutostartInterval, "min-autostart-interval", "", 0, "Edit the template minimum autostart interval - workspaces created from this template must wait at least this long between autostarts.") cliui.AllowSkipPrompt(cmd) return cmd diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index e2b9f09f3c37f..a2806b45120db 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -1456,7 +1456,6 @@ func (q *fakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.Upd tpl.Description = arg.Description tpl.Icon = arg.Icon tpl.MaxTtl = arg.MaxTtl - tpl.MinAutostartInterval = arg.MinAutostartInterval q.templates[idx] = tpl return tpl, nil } @@ -2227,25 +2226,20 @@ func (q *fakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl q.mutex.Lock() defer q.mutex.Unlock() - if arg.MinAutostartInterval == 0 { - arg.MinAutostartInterval = int64(time.Hour) - } - //nolint:gosimple template := database.Template{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - OrganizationID: arg.OrganizationID, - Name: arg.Name, - Provisioner: arg.Provisioner, - ActiveVersionID: arg.ActiveVersionID, - Description: arg.Description, - MaxTtl: arg.MaxTtl, - MinAutostartInterval: arg.MinAutostartInterval, - CreatedBy: arg.CreatedBy, - UserACL: arg.UserACL, - GroupACL: arg.GroupACL, + ID: arg.ID, + CreatedAt: arg.CreatedAt, + UpdatedAt: arg.UpdatedAt, + OrganizationID: arg.OrganizationID, + Name: arg.Name, + Provisioner: arg.Provisioner, + ActiveVersionID: arg.ActiveVersionID, + Description: arg.Description, + MaxTtl: arg.MaxTtl, + CreatedBy: arg.CreatedBy, + UserACL: arg.UserACL, + GroupACL: arg.GroupACL, } q.templates = append(q.templates, template) return template, nil diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 7c1bf4bfcd34d..6f89f8fc22767 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -3229,31 +3229,29 @@ INSERT INTO active_version_id, description, max_ttl, - min_autostart_interval, created_by, icon, user_acl, group_acl ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl ` type InsertTemplateParams struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` - Name string `db:"name" json:"name"` - Provisioner ProvisionerType `db:"provisioner" json:"provisioner"` - ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"` - Description string `db:"description" json:"description"` - MaxTtl int64 `db:"max_ttl" json:"max_ttl"` - MinAutostartInterval int64 `db:"min_autostart_interval" json:"min_autostart_interval"` - CreatedBy uuid.UUID `db:"created_by" json:"created_by"` - Icon string `db:"icon" json:"icon"` - UserACL TemplateACL `db:"user_acl" json:"user_acl"` - GroupACL TemplateACL `db:"group_acl" json:"group_acl"` + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` + Name string `db:"name" json:"name"` + Provisioner ProvisionerType `db:"provisioner" json:"provisioner"` + ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"` + Description string `db:"description" json:"description"` + MaxTtl int64 `db:"max_ttl" json:"max_ttl"` + CreatedBy uuid.UUID `db:"created_by" json:"created_by"` + Icon string `db:"icon" json:"icon"` + UserACL TemplateACL `db:"user_acl" json:"user_acl"` + GroupACL TemplateACL `db:"group_acl" json:"group_acl"` } func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParams) (Template, error) { @@ -3267,7 +3265,6 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam arg.ActiveVersionID, arg.Description, arg.MaxTtl, - arg.MinAutostartInterval, arg.CreatedBy, arg.Icon, arg.UserACL, @@ -3384,9 +3381,8 @@ SET updated_at = $2, description = $3, max_ttl = $4, - min_autostart_interval = $5, - name = $6, - icon = $7 + name = $5, + icon = $6 WHERE id = $1 RETURNING @@ -3394,13 +3390,12 @@ RETURNING ` type UpdateTemplateMetaByIDParams struct { - ID uuid.UUID `db:"id" json:"id"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - Description string `db:"description" json:"description"` - MaxTtl int64 `db:"max_ttl" json:"max_ttl"` - MinAutostartInterval int64 `db:"min_autostart_interval" json:"min_autostart_interval"` - Name string `db:"name" json:"name"` - Icon string `db:"icon" json:"icon"` + ID uuid.UUID `db:"id" json:"id"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + Description string `db:"description" json:"description"` + MaxTtl int64 `db:"max_ttl" json:"max_ttl"` + Name string `db:"name" json:"name"` + Icon string `db:"icon" json:"icon"` } func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) (Template, error) { @@ -3409,7 +3404,6 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl arg.UpdatedAt, arg.Description, arg.MaxTtl, - arg.MinAutostartInterval, arg.Name, arg.Icon, ) diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql index 6eb73af288b81..64df1cd25a440 100644 --- a/coderd/database/queries/templates.sql +++ b/coderd/database/queries/templates.sql @@ -66,14 +66,13 @@ INSERT INTO active_version_id, description, max_ttl, - min_autostart_interval, created_by, icon, user_acl, group_acl ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING *; + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING *; -- name: UpdateTemplateActiveVersionByID :exec UPDATE @@ -100,9 +99,8 @@ SET updated_at = $2, description = $3, max_ttl = $4, - min_autostart_interval = $5, - name = $6, - icon = $7 + name = $5, + icon = $6 WHERE id = $1 RETURNING diff --git a/coderd/templates.go b/coderd/templates.go index 163464db39b12..d342c990e8be7 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -22,7 +22,6 @@ import ( "github.com/coder/coder/coderd/httpmw" "github.com/coder/coder/coderd/rbac" "github.com/coder/coder/coderd/telemetry" - "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) @@ -236,28 +235,22 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque return } - minAutostartInterval := minAutostartIntervalDefault - if !ptr.NilOrZero(createTemplate.MinAutostartIntervalMillis) { - minAutostartInterval = time.Duration(*createTemplate.MinAutostartIntervalMillis) * time.Millisecond - } - var dbTemplate database.Template var template codersdk.Template err = api.Database.InTx(func(tx database.Store) error { now := database.Now() dbTemplate, err = tx.InsertTemplate(ctx, database.InsertTemplateParams{ - ID: uuid.New(), - CreatedAt: now, - UpdatedAt: now, - OrganizationID: organization.ID, - Name: createTemplate.Name, - Provisioner: importJob.Provisioner, - ActiveVersionID: templateVersion.ID, - Description: createTemplate.Description, - MaxTtl: int64(maxTTL), - MinAutostartInterval: int64(minAutostartInterval), - CreatedBy: apiKey.UserID, - UserACL: database.TemplateACL{}, + ID: uuid.New(), + CreatedAt: now, + UpdatedAt: now, + OrganizationID: organization.ID, + Name: createTemplate.Name, + Provisioner: importJob.Provisioner, + ActiveVersionID: templateVersion.ID, + Description: createTemplate.Description, + MaxTtl: int64(maxTTL), + CreatedBy: apiKey.UserID, + UserACL: database.TemplateACL{}, GroupACL: database.TemplateACL{ organization.ID.String(): []rbac.Action{rbac.ActionRead}, }, @@ -467,9 +460,6 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { if req.MaxTTLMillis < 0 { validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."}) } - if req.MinAutostartIntervalMillis < 0 { - validErrs = append(validErrs, codersdk.ValidationError{Field: "min_autostart_interval_ms", Detail: "Must be a positive integer."}) - } if req.MaxTTLMillis > maxTTLDefault.Milliseconds() { validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Cannot be greater than " + maxTTLDefault.String()}) } @@ -501,8 +491,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { if req.Name == template.Name && req.Description == template.Description && req.Icon == template.Icon && - req.MaxTTLMillis == time.Duration(template.MaxTtl).Milliseconds() && - req.MinAutostartIntervalMillis == time.Duration(template.MinAutostartInterval).Milliseconds() { + req.MaxTTLMillis == time.Duration(template.MaxTtl).Milliseconds() { return nil } @@ -511,7 +500,6 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { desc := req.Description icon := req.Icon maxTTL := time.Duration(req.MaxTTLMillis) * time.Millisecond - minAutostartInterval := time.Duration(req.MinAutostartIntervalMillis) * time.Millisecond if name == "" { name = template.Name @@ -519,18 +507,14 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { if desc == "" { desc = template.Description } - if minAutostartInterval == 0 { - minAutostartInterval = time.Duration(template.MinAutostartInterval) - } updated, err = tx.UpdateTemplateMetaByID(ctx, database.UpdateTemplateMetaByIDParams{ - ID: template.ID, - UpdatedAt: database.Now(), - Name: name, - Description: desc, - Icon: icon, - MaxTtl: int64(maxTTL), - MinAutostartInterval: int64(minAutostartInterval), + ID: template.ID, + UpdatedAt: database.Now(), + Name: name, + Description: desc, + Icon: icon, + MaxTtl: int64(maxTTL), }) if err != nil { return err @@ -666,18 +650,17 @@ func (api *API) autoImportTemplate(ctx context.Context, opts autoImportTemplateO // Create template template, err = tx.InsertTemplate(ctx, database.InsertTemplateParams{ - ID: uuid.New(), - CreatedAt: now, - UpdatedAt: now, - OrganizationID: opts.orgID, - Name: opts.name, - Provisioner: job.Provisioner, - ActiveVersionID: templateVersion.ID, - Description: "This template was auto-imported by Coder.", - MaxTtl: int64(maxTTLDefault), - MinAutostartInterval: int64(minAutostartIntervalDefault), - CreatedBy: opts.userID, - UserACL: database.TemplateACL{}, + ID: uuid.New(), + CreatedAt: now, + UpdatedAt: now, + OrganizationID: opts.orgID, + Name: opts.name, + Provisioner: job.Provisioner, + ActiveVersionID: templateVersion.ID, + Description: "This template was auto-imported by Coder.", + MaxTtl: int64(maxTTLDefault), + CreatedBy: opts.userID, + UserACL: database.TemplateACL{}, GroupACL: database.TemplateACL{ opts.orgID.String(): []rbac.Action{rbac.ActionRead}, }, diff --git a/coderd/templates_test.go b/coderd/templates_test.go index bb602d0b05406..b72e98515435b 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -310,11 +310,10 @@ func TestPatchTemplateMeta(t *testing.T) { ctr.MinAutostartIntervalMillis = ptr.Ref(time.Hour.Milliseconds()) }) req := codersdk.UpdateTemplateMeta{ - Name: "new-template-name", - Description: "lorem ipsum dolor sit amet et cetera", - Icon: "/icons/new-icon.png", - MaxTTLMillis: 12 * time.Hour.Milliseconds(), - MinAutostartIntervalMillis: time.Minute.Milliseconds(), + Name: "new-template-name", + Description: "lorem ipsum dolor sit amet et cetera", + Icon: "/icons/new-icon.png", + MaxTTLMillis: 12 * time.Hour.Milliseconds(), } // It is unfortunate we need to sleep, but the test can fail if the // updatedAt is too close together. @@ -330,7 +329,6 @@ func TestPatchTemplateMeta(t *testing.T) { assert.Equal(t, req.Description, updated.Description) assert.Equal(t, req.Icon, updated.Icon) assert.Equal(t, req.MaxTTLMillis, updated.MaxTTLMillis) - assert.Equal(t, req.MinAutostartIntervalMillis, updated.MinAutostartIntervalMillis) // Extra paranoid: did it _really_ happen? updated, err = client.Template(ctx, template.ID) @@ -340,7 +338,6 @@ func TestPatchTemplateMeta(t *testing.T) { assert.Equal(t, req.Description, updated.Description) assert.Equal(t, req.Icon, updated.Icon) assert.Equal(t, req.MaxTTLMillis, updated.MaxTTLMillis) - assert.Equal(t, req.MinAutostartIntervalMillis, updated.MinAutostartIntervalMillis) require.Len(t, auditor.AuditLogs, 4) assert.Equal(t, database.AuditActionWrite, auditor.AuditLogs[3].Action) @@ -444,11 +441,10 @@ func TestPatchTemplateMeta(t *testing.T) { defer cancel() req := codersdk.UpdateTemplateMeta{ - Name: template.Name, - Description: template.Description, - Icon: template.Icon, - MaxTTLMillis: template.MaxTTLMillis, - MinAutostartIntervalMillis: template.MinAutostartIntervalMillis, + Name: template.Name, + Description: template.Description, + Icon: template.Icon, + MaxTTLMillis: template.MaxTTLMillis, } _, err := client.UpdateTemplateMeta(ctx, template.ID, req) require.ErrorContains(t, err, "not modified") @@ -478,8 +474,7 @@ func TestPatchTemplateMeta(t *testing.T) { defer cancel() req := codersdk.UpdateTemplateMeta{ - MaxTTLMillis: -int64(time.Hour), - MinAutostartIntervalMillis: -int64(time.Hour), + MaxTTLMillis: -int64(time.Hour), } _, err := client.UpdateTemplateMeta(ctx, template.ID, req) var apiErr *codersdk.Error @@ -487,7 +482,6 @@ func TestPatchTemplateMeta(t *testing.T) { require.Contains(t, apiErr.Message, "Invalid request") require.Len(t, apiErr.Validations, 2) assert.Equal(t, apiErr.Validations[0].Field, "max_ttl_ms") - assert.Equal(t, apiErr.Validations[1].Field, "min_autostart_interval_ms") updated, err := client.Template(ctx, template.ID) require.NoError(t, err) diff --git a/codersdk/templates.go b/codersdk/templates.go index 22e707050aed3..6a723a665b3ab 100644 --- a/codersdk/templates.go +++ b/codersdk/templates.go @@ -72,11 +72,10 @@ type UpdateTemplateACL struct { } type UpdateTemplateMeta struct { - Name string `json:"name,omitempty" validate:"omitempty,username"` - Description string `json:"description,omitempty"` - Icon string `json:"icon,omitempty"` - MaxTTLMillis int64 `json:"max_ttl_ms,omitempty"` - MinAutostartIntervalMillis int64 `json:"min_autostart_interval_ms,omitempty"` + Name string `json:"name,omitempty" validate:"omitempty,username"` + Description string `json:"description,omitempty"` + Icon string `json:"icon,omitempty"` + MaxTTLMillis int64 `json:"max_ttl_ms,omitempty"` } // Template returns a single template. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index b38ed2ea6c040..59796976b3ab1 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -701,7 +701,6 @@ export interface UpdateTemplateMeta { readonly description?: string readonly icon?: string readonly max_ttl_ms?: number - readonly min_autostart_interval_ms?: number } // From codersdk/users.go From 04fd355738d79baa3267f3de03ee86548a6a2e99 Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 1 Nov 2022 19:48:11 +0000 Subject: [PATCH 02/18] drop column from db --- coderd/database/migrations/000069_remove_min_autostart.down.sql | 2 ++ coderd/database/migrations/000069_remove_min_autostart.up.sql | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 coderd/database/migrations/000069_remove_min_autostart.down.sql create mode 100644 coderd/database/migrations/000069_remove_min_autostart.up.sql diff --git a/coderd/database/migrations/000069_remove_min_autostart.down.sql b/coderd/database/migrations/000069_remove_min_autostart.down.sql new file mode 100644 index 0000000000000..8f7f7743a4a9f --- /dev/null +++ b/coderd/database/migrations/000069_remove_min_autostart.down.sql @@ -0,0 +1,2 @@ +-- add "slug" min_autostart_interval to "templates" table +ALTER TABLE "templates" ADD COLUMN "min_autostart_interval" int DEFAULT 0; diff --git a/coderd/database/migrations/000069_remove_min_autostart.up.sql b/coderd/database/migrations/000069_remove_min_autostart.up.sql new file mode 100644 index 0000000000000..cf2c8a7981a2c --- /dev/null +++ b/coderd/database/migrations/000069_remove_min_autostart.up.sql @@ -0,0 +1,2 @@ +-- drop "min_autostart_interval" column from "templates" table +ALTER TABLE "templates" DROP COLUMN "min_autostart_interval"; From 21a5c8e21fc83e8d61872bb8fa305b04d8a51fef Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 1 Nov 2022 19:48:53 +0000 Subject: [PATCH 03/18] lint --- coderd/templates.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/coderd/templates.go b/coderd/templates.go index d342c990e8be7..29fee72e9bdb7 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -26,8 +26,7 @@ import ( ) var ( - maxTTLDefault = 24 * 7 * time.Hour - minAutostartIntervalDefault = time.Hour + maxTTLDefault = 24 * 7 * time.Hour ) // Auto-importable templates. These can be auto-imported after the first user From 71875fd308f8a5d8e01b5a0870662e114b573ca9 Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 1 Nov 2022 19:50:58 +0000 Subject: [PATCH 04/18] go tests --- coderd/templates_test.go | 2 +- coderd/workspaces_test.go | 26 -------------------------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/coderd/templates_test.go b/coderd/templates_test.go index b72e98515435b..9a6e18f28cdb7 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -480,7 +480,7 @@ func TestPatchTemplateMeta(t *testing.T) { var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Contains(t, apiErr.Message, "Invalid request") - require.Len(t, apiErr.Validations, 2) + require.Len(t, apiErr.Validations, 1) assert.Equal(t, apiErr.Validations[0].Field, "max_ttl_ms") updated, err := client.Template(ctx, template.ID) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index ca92537da0e27..36ac0565600e8 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -325,32 +325,6 @@ func TestPostWorkspacesByOrganization(t *testing.T) { require.Equal(t, "time until shutdown must be less than 7 days", apiErr.Validations[0].Detail) }) }) - - t.Run("InvalidAutostart", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - req := codersdk.CreateWorkspaceRequest{ - TemplateID: template.ID, - Name: "testing", - AutostartSchedule: ptr.Ref("CRON_TZ=US/Central * * * * *"), - } - _, err := client.CreateWorkspace(ctx, template.OrganizationID, codersdk.Me, req) - require.Error(t, err) - var apiErr *codersdk.Error - require.ErrorAs(t, err, &apiErr) - require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) - require.Len(t, apiErr.Validations, 1) - require.Equal(t, apiErr.Validations[0].Field, "schedule") - require.Equal(t, apiErr.Validations[0].Detail, "Minimum autostart interval 1m0s below template minimum 1h0m0s") - }) } func TestWorkspaceByOwnerAndName(t *testing.T) { From 6fdd314db69006c4bde31e43e76afb4aaaabad8c Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 1 Nov 2022 19:55:37 +0000 Subject: [PATCH 05/18] make gen --- coderd/database/dump.sql | 1 - coderd/database/models.go | 29 +++++++++++----------- coderd/database/queries.sql.go | 21 ++++++---------- coderd/templates.go | 31 ++++++++++++----------- coderd/workspaces.go | 21 +++------------- enterprise/audit/diff_internal_test.go | 34 ++++++++++++-------------- 6 files changed, 56 insertions(+), 81 deletions(-) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index a32ea8af471f1..e097fcc306da8 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -350,7 +350,6 @@ CREATE TABLE templates ( active_version_id uuid NOT NULL, description character varying(128) DEFAULT ''::character varying NOT NULL, max_ttl bigint DEFAULT '604800000000000'::bigint NOT NULL, - min_autostart_interval bigint DEFAULT '3600000000000'::bigint NOT NULL, created_by uuid NOT NULL, icon character varying(256) DEFAULT ''::character varying NOT NULL, user_acl jsonb DEFAULT '{}'::jsonb NOT NULL, diff --git a/coderd/database/models.go b/coderd/database/models.go index b3da222afa827..b5d911be8c423 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -574,21 +574,20 @@ type SiteConfig struct { } type Template struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` - Deleted bool `db:"deleted" json:"deleted"` - Name string `db:"name" json:"name"` - Provisioner ProvisionerType `db:"provisioner" json:"provisioner"` - ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"` - Description string `db:"description" json:"description"` - MaxTtl int64 `db:"max_ttl" json:"max_ttl"` - MinAutostartInterval int64 `db:"min_autostart_interval" json:"min_autostart_interval"` - CreatedBy uuid.UUID `db:"created_by" json:"created_by"` - Icon string `db:"icon" json:"icon"` - UserACL TemplateACL `db:"user_acl" json:"user_acl"` - GroupACL TemplateACL `db:"group_acl" json:"group_acl"` + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` + Deleted bool `db:"deleted" json:"deleted"` + Name string `db:"name" json:"name"` + Provisioner ProvisionerType `db:"provisioner" json:"provisioner"` + ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"` + Description string `db:"description" json:"description"` + MaxTtl int64 `db:"max_ttl" json:"max_ttl"` + CreatedBy uuid.UUID `db:"created_by" json:"created_by"` + Icon string `db:"icon" json:"icon"` + UserACL TemplateACL `db:"user_acl" json:"user_acl"` + GroupACL TemplateACL `db:"group_acl" json:"group_acl"` } type TemplateVersion struct { diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 6f89f8fc22767..0924d5b20fc76 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -3019,7 +3019,7 @@ func (q *sqlQuerier) GetTemplateAverageBuildTime(ctx context.Context, arg GetTem const getTemplateByID = `-- name: GetTemplateByID :one SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl FROM templates WHERE @@ -3042,7 +3042,6 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat &i.ActiveVersionID, &i.Description, &i.MaxTtl, - &i.MinAutostartInterval, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3053,7 +3052,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl FROM templates WHERE @@ -3084,7 +3083,6 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G &i.ActiveVersionID, &i.Description, &i.MaxTtl, - &i.MinAutostartInterval, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3094,7 +3092,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G } const getTemplates = `-- name: GetTemplates :many -SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl FROM templates +SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl FROM templates ORDER BY (name, id) ASC ` @@ -3118,7 +3116,6 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) { &i.ActiveVersionID, &i.Description, &i.MaxTtl, - &i.MinAutostartInterval, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3139,7 +3136,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) { const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl FROM templates WHERE @@ -3198,7 +3195,6 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate &i.ActiveVersionID, &i.Description, &i.MaxTtl, - &i.MinAutostartInterval, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3235,7 +3231,7 @@ INSERT INTO group_acl ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl ` type InsertTemplateParams struct { @@ -3282,7 +3278,6 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam &i.ActiveVersionID, &i.Description, &i.MaxTtl, - &i.MinAutostartInterval, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3300,7 +3295,7 @@ SET WHERE id = $3 RETURNING - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl ` type UpdateTemplateACLByIDParams struct { @@ -3323,7 +3318,6 @@ func (q *sqlQuerier) UpdateTemplateACLByID(ctx context.Context, arg UpdateTempla &i.ActiveVersionID, &i.Description, &i.MaxTtl, - &i.MinAutostartInterval, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3386,7 +3380,7 @@ SET WHERE id = $1 RETURNING - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, min_autostart_interval, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl ` type UpdateTemplateMetaByIDParams struct { @@ -3419,7 +3413,6 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl &i.ActiveVersionID, &i.Description, &i.MaxTtl, - &i.MinAutostartInterval, &i.CreatedBy, &i.Icon, &i.UserACL, diff --git a/coderd/templates.go b/coderd/templates.go index 29fee72e9bdb7..9da7617f99bcf 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -750,21 +750,20 @@ func (api *API) convertTemplate( buildTimeStats := api.metricsCache.TemplateBuildTimeStats(template.ID) return codersdk.Template{ - ID: template.ID, - CreatedAt: template.CreatedAt, - UpdatedAt: template.UpdatedAt, - OrganizationID: template.OrganizationID, - Name: template.Name, - Provisioner: codersdk.ProvisionerType(template.Provisioner), - ActiveVersionID: template.ActiveVersionID, - WorkspaceOwnerCount: workspaceOwnerCount, - ActiveUserCount: activeCount, - BuildTimeStats: buildTimeStats, - Description: template.Description, - Icon: template.Icon, - MaxTTLMillis: time.Duration(template.MaxTtl).Milliseconds(), - MinAutostartIntervalMillis: time.Duration(template.MinAutostartInterval).Milliseconds(), - CreatedByID: template.CreatedBy, - CreatedByName: createdByName, + ID: template.ID, + CreatedAt: template.CreatedAt, + UpdatedAt: template.UpdatedAt, + OrganizationID: template.OrganizationID, + Name: template.Name, + Provisioner: codersdk.ProvisionerType(template.Provisioner), + ActiveVersionID: template.ActiveVersionID, + WorkspaceOwnerCount: workspaceOwnerCount, + ActiveUserCount: activeCount, + BuildTimeStats: buildTimeStats, + Description: template.Description, + Icon: template.Icon, + MaxTTLMillis: time.Duration(template.MaxTtl).Milliseconds(), + CreatedByID: template.CreatedBy, + CreatedByName: createdByName, } } diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 38d53107363dd..28d5a1124e701 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -333,7 +333,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req return } - dbAutostartSchedule, err := validWorkspaceSchedule(createWorkspace.AutostartSchedule, time.Duration(template.MinAutostartInterval)) + dbAutostartSchedule, err := validWorkspaceSchedule(createWorkspace.AutostartSchedule) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid Autostart Schedule.", @@ -666,16 +666,7 @@ func (api *API) putWorkspaceAutostart(rw http.ResponseWriter, r *http.Request) { return } - template, err := api.Database.GetTemplateByID(ctx, workspace.TemplateID) - if err != nil { - api.Logger.Error(ctx, "fetch workspace template", slog.F("workspace_id", workspace.ID), slog.F("template_id", workspace.TemplateID), slog.Error(err)) - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Error fetching workspace template.", - }) - return - } - - dbSched, err := validWorkspaceSchedule(req.Schedule, time.Duration(template.MinAutostartInterval)) + dbSched, err := validWorkspaceSchedule(req.Schedule) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid autostart schedule.", @@ -1149,20 +1140,16 @@ func validWorkspaceDeadline(startedAt, newDeadline time.Time, max time.Duration) return nil } -func validWorkspaceSchedule(s *string, min time.Duration) (sql.NullString, error) { +func validWorkspaceSchedule(s *string) (sql.NullString, error) { if ptr.NilOrEmpty(s) { return sql.NullString{}, nil } - sched, err := schedule.Weekly(*s) + _, err := schedule.Weekly(*s) if err != nil { return sql.NullString{}, err } - if schedMin := sched.Min(); schedMin < min { - return sql.NullString{}, xerrors.Errorf("Minimum autostart interval %s below template minimum %s", schedMin, min) - } - return sql.NullString{ Valid: true, String: *s, diff --git a/enterprise/audit/diff_internal_test.go b/enterprise/audit/diff_internal_test.go index d5ee1f0e369c5..ea4bab2fff7c0 100644 --- a/enterprise/audit/diff_internal_test.go +++ b/enterprise/audit/diff_internal_test.go @@ -242,26 +242,24 @@ func Test_diff(t *testing.T) { name: "Create", left: audit.Empty[database.Template](), right: database.Template{ - ID: uuid.UUID{1}, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - OrganizationID: uuid.UUID{2}, - Deleted: false, - Name: "rust", - Provisioner: database.ProvisionerTypeTerraform, - ActiveVersionID: uuid.UUID{3}, - MaxTtl: int64(time.Hour), - MinAutostartInterval: int64(time.Minute), - CreatedBy: uuid.UUID{4}, + ID: uuid.UUID{1}, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + OrganizationID: uuid.UUID{2}, + Deleted: false, + Name: "rust", + Provisioner: database.ProvisionerTypeTerraform, + ActiveVersionID: uuid.UUID{3}, + MaxTtl: int64(time.Hour), + CreatedBy: uuid.UUID{4}, }, exp: audit.Map{ - "id": audit.OldNew{Old: "", New: uuid.UUID{1}.String()}, - "name": audit.OldNew{Old: "", New: "rust"}, - "provisioner": audit.OldNew{Old: database.ProvisionerType(""), New: database.ProvisionerTypeTerraform}, - "active_version_id": audit.OldNew{Old: "", New: uuid.UUID{3}.String()}, - "max_ttl": audit.OldNew{Old: int64(0), New: int64(time.Hour)}, - "min_autostart_interval": audit.OldNew{Old: int64(0), New: int64(time.Minute)}, - "created_by": audit.OldNew{Old: "", New: uuid.UUID{4}.String()}, + "id": audit.OldNew{Old: "", New: uuid.UUID{1}.String()}, + "name": audit.OldNew{Old: "", New: "rust"}, + "provisioner": audit.OldNew{Old: database.ProvisionerType(""), New: database.ProvisionerTypeTerraform}, + "active_version_id": audit.OldNew{Old: "", New: uuid.UUID{3}.String()}, + "max_ttl": audit.OldNew{Old: int64(0), New: int64(time.Hour)}, + "created_by": audit.OldNew{Old: "", New: uuid.UUID{4}.String()}, }, }, }) From 0f5e78916974a41960aa1f64c238a96f9bb7f3dc Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 1 Nov 2022 20:12:52 +0000 Subject: [PATCH 06/18] change max-ttl to default --- cli/templatecreate.go | 11 ++- cli/templatecreate_test.go | 1 - cli/templateedit.go | 12 +-- cli/templateedit_test.go | 20 ++--- cli/templates.go | 2 +- coderd/database/databasefake/databasefake.go | 4 +- coderd/database/dump.sql | 2 +- .../000069_remove_min_autostart.down.sql | 3 + .../000069_remove_min_autostart.up.sql | 3 + coderd/database/models.go | 2 +- coderd/database/queries.sql.go | 40 +++++----- coderd/database/queries/templates.sql | 4 +- coderd/templates.go | 32 ++++---- coderd/templates_test.go | 73 +++++++++---------- coderd/workspaces.go | 6 +- coderd/workspaces_test.go | 28 +++---- codersdk/organizations.go | 9 +-- codersdk/templates.go | 10 +-- enterprise/audit/diff_internal_test.go | 2 +- 19 files changed, 128 insertions(+), 136 deletions(-) diff --git a/cli/templatecreate.go b/cli/templatecreate.go index 458cb1c2015b0..c53316a66edff 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -27,7 +27,7 @@ func templateCreate() *cobra.Command { directory string provisioner string parameterFile string - maxTTL time.Duration + defaultTTL time.Duration minAutostartInterval time.Duration ) cmd := &cobra.Command{ @@ -108,10 +108,9 @@ func templateCreate() *cobra.Command { } createReq := codersdk.CreateTemplateRequest{ - Name: templateName, - VersionID: job.ID, - MaxTTLMillis: ptr.Ref(maxTTL.Milliseconds()), - MinAutostartIntervalMillis: ptr.Ref(minAutostartInterval.Milliseconds()), + Name: templateName, + VersionID: job.ID, + DefaultTTLMillis: ptr.Ref(defaultTTL.Milliseconds()), } _, err = client.CreateTemplate(cmd.Context(), organization.ID, createReq) @@ -133,7 +132,7 @@ func templateCreate() *cobra.Command { cmd.Flags().StringVarP(&directory, "directory", "d", currentDirectory, "Specify the directory to create from") cmd.Flags().StringVarP(&provisioner, "test.provisioner", "", "terraform", "Customize the provisioner backend") cmd.Flags().StringVarP(¶meterFile, "parameter-file", "", "", "Specify a file path with parameter values.") - cmd.Flags().DurationVarP(&maxTTL, "max-ttl", "", 24*time.Hour, "Specify a maximum TTL for workspaces created from this template.") + cmd.Flags().DurationVarP(&defaultTTL, "default-ttl", "", 24*time.Hour, "Specify a default TTL for workspaces created from this template.") cmd.Flags().DurationVarP(&minAutostartInterval, "min-autostart-interval", "", time.Hour, "Specify a minimum autostart interval for workspaces created from this template.") // This is for testing! err := cmd.Flags().MarkHidden("test.provisioner") diff --git a/cli/templatecreate_test.go b/cli/templatecreate_test.go index ccffb45fc7114..cca46c29ee737 100644 --- a/cli/templatecreate_test.go +++ b/cli/templatecreate_test.go @@ -53,7 +53,6 @@ func TestTemplateCreate(t *testing.T) { "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--max-ttl", "24h", - "--min-autostart-interval", "2h", } cmd, root := clitest.New(t, args...) clitest.SetupConfig(t, client, root) diff --git a/cli/templateedit.go b/cli/templateedit.go index 09bdf5e069960..867cb41d208a7 100644 --- a/cli/templateedit.go +++ b/cli/templateedit.go @@ -16,7 +16,7 @@ func templateEdit() *cobra.Command { name string description string icon string - maxTTL time.Duration + defaultTTL time.Duration ) cmd := &cobra.Command{ @@ -39,10 +39,10 @@ func templateEdit() *cobra.Command { // NOTE: coderd will ignore empty fields. req := codersdk.UpdateTemplateMeta{ - Name: name, - Description: description, - Icon: icon, - MaxTTLMillis: maxTTL.Milliseconds(), + Name: name, + Description: description, + Icon: icon, + DefaultTTLMillis: defaultTTL.Milliseconds(), } _, err = client.UpdateTemplateMeta(cmd.Context(), template.ID, req) @@ -57,7 +57,7 @@ func templateEdit() *cobra.Command { cmd.Flags().StringVarP(&name, "name", "", "", "Edit the template name") cmd.Flags().StringVarP(&description, "description", "", "", "Edit the template description") cmd.Flags().StringVarP(&icon, "icon", "", "", "Edit the template icon path") - cmd.Flags().DurationVarP(&maxTTL, "max-ttl", "", 0, "Edit the template maximum time before shutdown - workspaces created from this template cannot stay running longer than this.") + cmd.Flags().DurationVarP(&defaultTTL, "default-ttl", "", 0, "Edit the template default time before shutdown - workspaces created from this template to this value.") cliui.AllowSkipPrompt(cmd) return cmd diff --git a/cli/templateedit_test.go b/cli/templateedit_test.go index 61437764021f6..3b66dd6d34b41 100644 --- a/cli/templateedit_test.go +++ b/cli/templateedit_test.go @@ -26,16 +26,14 @@ func TestTemplateEdit(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.Description = "original description" ctr.Icon = "/icons/default-icon.png" - ctr.MaxTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) - ctr.MinAutostartIntervalMillis = ptr.Ref(time.Hour.Milliseconds()) + ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) }) // Test the cli command. name := "new-template-name" desc := "lorem ipsum dolor sit amet et cetera" icon := "/icons/new-icon.png" - maxTTL := 12 * time.Hour - minAutostartInterval := time.Minute + defaultTTL := 12 * time.Hour cmdArgs := []string{ "templates", "edit", @@ -43,8 +41,7 @@ func TestTemplateEdit(t *testing.T) { "--name", name, "--description", desc, "--icon", icon, - "--max-ttl", maxTTL.String(), - "--min-autostart-interval", minAutostartInterval.String(), + "--default-ttl", defaultTTL.String(), } cmd, root := clitest.New(t, cmdArgs...) clitest.SetupConfig(t, client, root) @@ -59,8 +56,7 @@ func TestTemplateEdit(t *testing.T) { assert.Equal(t, name, updated.Name) assert.Equal(t, desc, updated.Description) assert.Equal(t, icon, updated.Icon) - assert.Equal(t, maxTTL.Milliseconds(), updated.MaxTTLMillis) - assert.Equal(t, minAutostartInterval.Milliseconds(), updated.MinAutostartIntervalMillis) + assert.Equal(t, defaultTTL.Milliseconds(), updated.DefaultTTLMillis) }) t.Run("NotModified", func(t *testing.T) { @@ -72,8 +68,7 @@ func TestTemplateEdit(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.Description = "original description" ctr.Icon = "/icons/default-icon.png" - ctr.MaxTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) - ctr.MinAutostartIntervalMillis = ptr.Ref(time.Hour.Milliseconds()) + ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) }) // Test the cli command. @@ -84,8 +79,7 @@ func TestTemplateEdit(t *testing.T) { "--name", template.Name, "--description", template.Description, "--icon", template.Icon, - "--max-ttl", (time.Duration(template.MaxTTLMillis) * time.Millisecond).String(), - "--min-autostart-interval", (time.Duration(template.MinAutostartIntervalMillis) * time.Millisecond).String(), + "--default-ttl", (time.Duration(template.DefaultTTLMillis) * time.Millisecond).String(), } cmd, root := clitest.New(t, cmdArgs...) clitest.SetupConfig(t, client, root) @@ -100,7 +94,7 @@ func TestTemplateEdit(t *testing.T) { assert.Equal(t, template.Name, updated.Name) assert.Equal(t, template.Description, updated.Description) assert.Equal(t, template.Icon, updated.Icon) - assert.Equal(t, template.MaxTTLMillis, updated.MaxTTLMillis) + assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis) assert.Equal(t, template.MinAutostartIntervalMillis, updated.MinAutostartIntervalMillis) }) } diff --git a/cli/templates.go b/cli/templates.go index 4c85606d70c6f..5d96805a153f8 100644 --- a/cli/templates.go +++ b/cli/templates.go @@ -75,7 +75,7 @@ func displayTemplates(filterColumns []string, templates ...codersdk.Template) (s Provisioner: template.Provisioner, ActiveVersionID: template.ActiveVersionID, UsedBy: cliui.Styles.Fuchsia.Render(formatActiveDevelopers(template.ActiveUserCount)), - MaxTTL: (time.Duration(template.MaxTTLMillis) * time.Millisecond), + MaxTTL: (time.Duration(template.DefaultTTLMillis) * time.Millisecond), MinAutostartInterval: (time.Duration(template.MinAutostartIntervalMillis) * time.Millisecond), } } diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index a2806b45120db..91525b5eb09af 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -1455,7 +1455,7 @@ func (q *fakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.Upd tpl.Name = arg.Name tpl.Description = arg.Description tpl.Icon = arg.Icon - tpl.MaxTtl = arg.MaxTtl + tpl.DefaultTtl = arg.DefaultTtl q.templates[idx] = tpl return tpl, nil } @@ -2236,7 +2236,7 @@ func (q *fakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl Provisioner: arg.Provisioner, ActiveVersionID: arg.ActiveVersionID, Description: arg.Description, - MaxTtl: arg.MaxTtl, + DefaultTtl: arg.DefaultTtl, CreatedBy: arg.CreatedBy, UserACL: arg.UserACL, GroupACL: arg.GroupACL, diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index e097fcc306da8..cb62c42fae208 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -349,7 +349,7 @@ CREATE TABLE templates ( provisioner provisioner_type NOT NULL, active_version_id uuid NOT NULL, description character varying(128) DEFAULT ''::character varying NOT NULL, - max_ttl bigint DEFAULT '604800000000000'::bigint NOT NULL, + default_ttl bigint DEFAULT '604800000000000'::bigint NOT NULL, created_by uuid NOT NULL, icon character varying(256) DEFAULT ''::character varying NOT NULL, user_acl jsonb DEFAULT '{}'::jsonb NOT NULL, diff --git a/coderd/database/migrations/000069_remove_min_autostart.down.sql b/coderd/database/migrations/000069_remove_min_autostart.down.sql index 8f7f7743a4a9f..0b7b72c9fc974 100644 --- a/coderd/database/migrations/000069_remove_min_autostart.down.sql +++ b/coderd/database/migrations/000069_remove_min_autostart.down.sql @@ -1,2 +1,5 @@ -- add "slug" min_autostart_interval to "templates" table ALTER TABLE "templates" ADD COLUMN "min_autostart_interval" int DEFAULT 0; + +-- rename "default_ttl" to "max_ttl" on "templates" table +ALTER TABLE "templates" RENAME COLUMN "default_ttl" TO "max_ttl"; diff --git a/coderd/database/migrations/000069_remove_min_autostart.up.sql b/coderd/database/migrations/000069_remove_min_autostart.up.sql index cf2c8a7981a2c..900e0afd59525 100644 --- a/coderd/database/migrations/000069_remove_min_autostart.up.sql +++ b/coderd/database/migrations/000069_remove_min_autostart.up.sql @@ -1,2 +1,5 @@ -- drop "min_autostart_interval" column from "templates" table ALTER TABLE "templates" DROP COLUMN "min_autostart_interval"; + +-- rename "max_ttl" to "default_ttl" on "templates" table +ALTER TABLE "templates" RENAME COLUMN "max_ttl" TO "default_ttl"; diff --git a/coderd/database/models.go b/coderd/database/models.go index b5d911be8c423..3d2b809b04d82 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -583,7 +583,7 @@ type Template struct { Provisioner ProvisionerType `db:"provisioner" json:"provisioner"` ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"` Description string `db:"description" json:"description"` - MaxTtl int64 `db:"max_ttl" json:"max_ttl"` + DefaultTtl int64 `db:"default_ttl" json:"default_ttl"` CreatedBy uuid.UUID `db:"created_by" json:"created_by"` Icon string `db:"icon" json:"icon"` UserACL TemplateACL `db:"user_acl" json:"user_acl"` diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 0924d5b20fc76..074bbb8a7eac3 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -3019,7 +3019,7 @@ func (q *sqlQuerier) GetTemplateAverageBuildTime(ctx context.Context, arg GetTem const getTemplateByID = `-- name: GetTemplateByID :one SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl FROM templates WHERE @@ -3041,7 +3041,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat &i.Provisioner, &i.ActiveVersionID, &i.Description, - &i.MaxTtl, + &i.DefaultTtl, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3052,7 +3052,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl FROM templates WHERE @@ -3082,7 +3082,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G &i.Provisioner, &i.ActiveVersionID, &i.Description, - &i.MaxTtl, + &i.DefaultTtl, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3092,7 +3092,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G } const getTemplates = `-- name: GetTemplates :many -SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl FROM templates +SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl FROM templates ORDER BY (name, id) ASC ` @@ -3115,7 +3115,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) { &i.Provisioner, &i.ActiveVersionID, &i.Description, - &i.MaxTtl, + &i.DefaultTtl, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3136,7 +3136,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) { const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many SELECT - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl FROM templates WHERE @@ -3194,7 +3194,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate &i.Provisioner, &i.ActiveVersionID, &i.Description, - &i.MaxTtl, + &i.DefaultTtl, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3224,14 +3224,14 @@ INSERT INTO provisioner, active_version_id, description, - max_ttl, + default_ttl, created_by, icon, user_acl, group_acl ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl ` type InsertTemplateParams struct { @@ -3243,7 +3243,7 @@ type InsertTemplateParams struct { Provisioner ProvisionerType `db:"provisioner" json:"provisioner"` ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"` Description string `db:"description" json:"description"` - MaxTtl int64 `db:"max_ttl" json:"max_ttl"` + DefaultTtl int64 `db:"default_ttl" json:"default_ttl"` CreatedBy uuid.UUID `db:"created_by" json:"created_by"` Icon string `db:"icon" json:"icon"` UserACL TemplateACL `db:"user_acl" json:"user_acl"` @@ -3260,7 +3260,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam arg.Provisioner, arg.ActiveVersionID, arg.Description, - arg.MaxTtl, + arg.DefaultTtl, arg.CreatedBy, arg.Icon, arg.UserACL, @@ -3277,7 +3277,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam &i.Provisioner, &i.ActiveVersionID, &i.Description, - &i.MaxTtl, + &i.DefaultTtl, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3295,7 +3295,7 @@ SET WHERE id = $3 RETURNING - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl ` type UpdateTemplateACLByIDParams struct { @@ -3317,7 +3317,7 @@ func (q *sqlQuerier) UpdateTemplateACLByID(ctx context.Context, arg UpdateTempla &i.Provisioner, &i.ActiveVersionID, &i.Description, - &i.MaxTtl, + &i.DefaultTtl, &i.CreatedBy, &i.Icon, &i.UserACL, @@ -3374,20 +3374,20 @@ UPDATE SET updated_at = $2, description = $3, - max_ttl = $4, + default_ttl = $4, name = $5, icon = $6 WHERE id = $1 RETURNING - id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, max_ttl, created_by, icon, user_acl, group_acl + id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl ` type UpdateTemplateMetaByIDParams struct { ID uuid.UUID `db:"id" json:"id"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` Description string `db:"description" json:"description"` - MaxTtl int64 `db:"max_ttl" json:"max_ttl"` + DefaultTtl int64 `db:"default_ttl" json:"default_ttl"` Name string `db:"name" json:"name"` Icon string `db:"icon" json:"icon"` } @@ -3397,7 +3397,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl arg.ID, arg.UpdatedAt, arg.Description, - arg.MaxTtl, + arg.DefaultTtl, arg.Name, arg.Icon, ) @@ -3412,7 +3412,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl &i.Provisioner, &i.ActiveVersionID, &i.Description, - &i.MaxTtl, + &i.DefaultTtl, &i.CreatedBy, &i.Icon, &i.UserACL, diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql index 64df1cd25a440..7063b87075c6f 100644 --- a/coderd/database/queries/templates.sql +++ b/coderd/database/queries/templates.sql @@ -65,7 +65,7 @@ INSERT INTO provisioner, active_version_id, description, - max_ttl, + default_ttl, created_by, icon, user_acl, @@ -98,7 +98,7 @@ UPDATE SET updated_at = $2, description = $3, - max_ttl = $4, + default_ttl = $4, name = $5, icon = $6 WHERE diff --git a/coderd/templates.go b/coderd/templates.go index 9da7617f99bcf..1703884bf35f9 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -26,7 +26,7 @@ import ( ) var ( - maxTTLDefault = 24 * 7 * time.Hour + defaultTTL = 24 * 7 * time.Hour ) // Auto-importable templates. These can be auto-imported after the first user @@ -210,9 +210,9 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque return } - maxTTL := maxTTLDefault - if createTemplate.MaxTTLMillis != nil { - maxTTL = time.Duration(*createTemplate.MaxTTLMillis) * time.Millisecond + maxTTL := defaultTTL + if createTemplate.DefaultTTLMillis != nil { + maxTTL = time.Duration(*createTemplate.DefaultTTLMillis) * time.Millisecond } if maxTTL < 0 { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ @@ -224,11 +224,11 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque return } - if maxTTL > maxTTLDefault { + if maxTTL > defaultTTL { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid create template request.", Validations: []codersdk.ValidationError{ - {Field: "max_ttl_ms", Detail: "Cannot be greater than " + maxTTLDefault.String()}, + {Field: "max_ttl_ms", Detail: "Cannot be greater than " + defaultTTL.String()}, }, }) return @@ -247,7 +247,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque Provisioner: importJob.Provisioner, ActiveVersionID: templateVersion.ID, Description: createTemplate.Description, - MaxTtl: int64(maxTTL), + DefaultTtl: int64(maxTTL), CreatedBy: apiKey.UserID, UserACL: database.TemplateACL{}, GroupACL: database.TemplateACL{ @@ -456,11 +456,11 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { } var validErrs []codersdk.ValidationError - if req.MaxTTLMillis < 0 { - validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."}) + if req.DefaultTTLMillis < 0 { + validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."}) } - if req.MaxTTLMillis > maxTTLDefault.Milliseconds() { - validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Cannot be greater than " + maxTTLDefault.String()}) + if req.DefaultTTLMillis > defaultTTL.Milliseconds() { + validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Cannot be greater than " + defaultTTL.String()}) } if len(validErrs) > 0 { @@ -490,7 +490,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { if req.Name == template.Name && req.Description == template.Description && req.Icon == template.Icon && - req.MaxTTLMillis == time.Duration(template.MaxTtl).Milliseconds() { + req.DefaultTTLMillis == time.Duration(template.DefaultTtl).Milliseconds() { return nil } @@ -498,7 +498,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { name := req.Name desc := req.Description icon := req.Icon - maxTTL := time.Duration(req.MaxTTLMillis) * time.Millisecond + maxTTL := time.Duration(req.DefaultTTLMillis) * time.Millisecond if name == "" { name = template.Name @@ -513,7 +513,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { Name: name, Description: desc, Icon: icon, - MaxTtl: int64(maxTTL), + DefaultTtl: int64(maxTTL), }) if err != nil { return err @@ -657,7 +657,7 @@ func (api *API) autoImportTemplate(ctx context.Context, opts autoImportTemplateO Provisioner: job.Provisioner, ActiveVersionID: templateVersion.ID, Description: "This template was auto-imported by Coder.", - MaxTtl: int64(maxTTLDefault), + DefaultTtl: int64(defaultTTL), CreatedBy: opts.userID, UserACL: database.TemplateACL{}, GroupACL: database.TemplateACL{ @@ -762,7 +762,7 @@ func (api *API) convertTemplate( BuildTimeStats: buildTimeStats, Description: template.Description, Icon: template.Icon, - MaxTTLMillis: time.Duration(template.MaxTtl).Milliseconds(), + DefaultTTLMillis: time.Duration(template.DefaultTtl).Milliseconds(), CreatedByID: template.CreatedBy, CreatedByName: createdByName, } diff --git a/coderd/templates_test.go b/coderd/templates_test.go index 9a6e18f28cdb7..d66cd4fb47b6e 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -131,9 +131,9 @@ func TestPostTemplateByOrganization(t *testing.T) { defer cancel() _, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{ - Name: "testing", - VersionID: version.ID, - MaxTTLMillis: ptr.Ref(int64(-1)), + Name: "testing", + VersionID: version.ID, + DefaultTTLMillis: ptr.Ref(int64(-1)), }) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) @@ -151,9 +151,9 @@ func TestPostTemplateByOrganization(t *testing.T) { defer cancel() _, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{ - Name: "testing", - VersionID: version.ID, - MaxTTLMillis: ptr.Ref(365 * 24 * time.Hour.Milliseconds()), + Name: "testing", + VersionID: version.ID, + DefaultTTLMillis: ptr.Ref(365 * 24 * time.Hour.Milliseconds()), }) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) @@ -171,12 +171,12 @@ func TestPostTemplateByOrganization(t *testing.T) { defer cancel() got, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{ - Name: "testing", - VersionID: version.ID, - MaxTTLMillis: ptr.Ref(int64(0)), + Name: "testing", + VersionID: version.ID, + DefaultTTLMillis: ptr.Ref(int64(0)), }) require.NoError(t, err) - require.Zero(t, got.MaxTTLMillis) + require.Zero(t, got.DefaultTTLMillis) }) t.Run("Unauthorized", func(t *testing.T) { @@ -306,14 +306,13 @@ func TestPatchTemplateMeta(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.Description = "original description" ctr.Icon = "/icons/original-icon.png" - ctr.MaxTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) - ctr.MinAutostartIntervalMillis = ptr.Ref(time.Hour.Milliseconds()) + ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) }) req := codersdk.UpdateTemplateMeta{ - Name: "new-template-name", - Description: "lorem ipsum dolor sit amet et cetera", - Icon: "/icons/new-icon.png", - MaxTTLMillis: 12 * time.Hour.Milliseconds(), + Name: "new-template-name", + Description: "lorem ipsum dolor sit amet et cetera", + Icon: "/icons/new-icon.png", + DefaultTTLMillis: 12 * time.Hour.Milliseconds(), } // It is unfortunate we need to sleep, but the test can fail if the // updatedAt is too close together. @@ -328,7 +327,7 @@ func TestPatchTemplateMeta(t *testing.T) { assert.Equal(t, req.Name, updated.Name) assert.Equal(t, req.Description, updated.Description) assert.Equal(t, req.Icon, updated.Icon) - assert.Equal(t, req.MaxTTLMillis, updated.MaxTTLMillis) + assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis) // Extra paranoid: did it _really_ happen? updated, err = client.Template(ctx, template.ID) @@ -337,7 +336,7 @@ func TestPatchTemplateMeta(t *testing.T) { assert.Equal(t, req.Name, updated.Name) assert.Equal(t, req.Description, updated.Description) assert.Equal(t, req.Icon, updated.Icon) - assert.Equal(t, req.MaxTTLMillis, updated.MaxTTLMillis) + assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis) require.Len(t, auditor.AuditLogs, 4) assert.Equal(t, database.AuditActionWrite, auditor.AuditLogs[3].Action) @@ -350,10 +349,10 @@ func TestPatchTemplateMeta(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { - ctr.MaxTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) + ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) }) req := codersdk.UpdateTemplateMeta{ - MaxTTLMillis: 0, + DefaultTTLMillis: 0, } // We're too fast! Sleep so we can be sure that updatedAt is greater @@ -369,7 +368,7 @@ func TestPatchTemplateMeta(t *testing.T) { updated, err := client.Template(ctx, template.ID) require.NoError(t, err) assert.Greater(t, updated.UpdatedAt, template.UpdatedAt) - assert.Equal(t, req.MaxTTLMillis, updated.MaxTTLMillis) + assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis) }) t.Run("MaxTTLTooLow", func(t *testing.T) { @@ -379,10 +378,10 @@ func TestPatchTemplateMeta(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { - ctr.MaxTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) + ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) }) req := codersdk.UpdateTemplateMeta{ - MaxTTLMillis: -1, + DefaultTTLMillis: -1, } ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -395,7 +394,7 @@ func TestPatchTemplateMeta(t *testing.T) { updated, err := client.Template(ctx, template.ID) require.NoError(t, err) assert.Equal(t, updated.UpdatedAt, template.UpdatedAt) - assert.Equal(t, updated.MaxTTLMillis, template.MaxTTLMillis) + assert.Equal(t, updated.DefaultTTLMillis, template.DefaultTTLMillis) }) t.Run("MaxTTLTooHigh", func(t *testing.T) { @@ -405,10 +404,10 @@ func TestPatchTemplateMeta(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { - ctr.MaxTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) + ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) }) req := codersdk.UpdateTemplateMeta{ - MaxTTLMillis: 365 * 24 * time.Hour.Milliseconds(), + DefaultTTLMillis: 365 * 24 * time.Hour.Milliseconds(), } ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -421,7 +420,7 @@ func TestPatchTemplateMeta(t *testing.T) { updated, err := client.Template(ctx, template.ID) require.NoError(t, err) assert.Equal(t, updated.UpdatedAt, template.UpdatedAt) - assert.Equal(t, updated.MaxTTLMillis, template.MaxTTLMillis) + assert.Equal(t, updated.DefaultTTLMillis, template.DefaultTTLMillis) }) t.Run("NotModified", func(t *testing.T) { @@ -433,18 +432,17 @@ func TestPatchTemplateMeta(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.Description = "original description" ctr.Icon = "/icons/original-icon.png" - ctr.MaxTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) - ctr.MinAutostartIntervalMillis = ptr.Ref(time.Hour.Milliseconds()) + ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) }) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() req := codersdk.UpdateTemplateMeta{ - Name: template.Name, - Description: template.Description, - Icon: template.Icon, - MaxTTLMillis: template.MaxTTLMillis, + Name: template.Name, + Description: template.Description, + Icon: template.Icon, + DefaultTTLMillis: template.DefaultTTLMillis, } _, err := client.UpdateTemplateMeta(ctx, template.ID, req) require.ErrorContains(t, err, "not modified") @@ -454,7 +452,7 @@ func TestPatchTemplateMeta(t *testing.T) { assert.Equal(t, template.Name, updated.Name) assert.Equal(t, template.Description, updated.Description) assert.Equal(t, template.Icon, updated.Icon) - assert.Equal(t, template.MaxTTLMillis, updated.MaxTTLMillis) + assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis) assert.Equal(t, template.MinAutostartIntervalMillis, updated.MinAutostartIntervalMillis) }) @@ -466,15 +464,14 @@ func TestPatchTemplateMeta(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.Description = "original description" - ctr.MaxTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) - ctr.MinAutostartIntervalMillis = ptr.Ref(time.Hour.Milliseconds()) + ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) }) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() req := codersdk.UpdateTemplateMeta{ - MaxTTLMillis: -int64(time.Hour), + DefaultTTLMillis: -int64(time.Hour), } _, err := client.UpdateTemplateMeta(ctx, template.ID, req) var apiErr *codersdk.Error @@ -489,7 +486,7 @@ func TestPatchTemplateMeta(t *testing.T) { assert.Equal(t, template.Name, updated.Name) assert.Equal(t, template.Description, updated.Description) assert.Equal(t, template.Icon, updated.Icon) - assert.Equal(t, template.MaxTTLMillis, updated.MaxTTLMillis) + assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis) assert.Equal(t, template.MinAutostartIntervalMillis, updated.MinAutostartIntervalMillis) }) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 28d5a1124e701..5fe0e1463c3fb 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -342,7 +342,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req return } - dbTTL, err := validWorkspaceTTLMillis(createWorkspace.TTLMillis, time.Duration(template.MaxTtl)) + dbTTL, err := validWorkspaceTTLMillis(createWorkspace.TTLMillis, time.Duration(template.DefaultTtl)) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid Workspace Time to Shutdown.", @@ -730,7 +730,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { return xerrors.Errorf("fetch workspace template: %w", err) } - dbTTL, err = validWorkspaceTTLMillis(req.TTLMillis, time.Duration(template.MaxTtl)) + dbTTL, err = validWorkspaceTTLMillis(req.TTLMillis, time.Duration(template.DefaultTtl)) if err != nil { return codersdk.ValidationError{Field: "ttl_ms", Detail: err.Error()} } @@ -824,7 +824,7 @@ 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 { + if err := validWorkspaceDeadline(job.CompletedAt.Time, newDeadline, time.Duration(template.DefaultTtl)); 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. diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 36ac0565600e8..b807037b96d05 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -239,10 +239,10 @@ func TestPostWorkspacesByOrganization(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { - ctr.MaxTTLMillis = ptr.Ref(int64(0)) + ctr.DefaultTTLMillis = ptr.Ref(int64(0)) }) // Given: the template has no max TTL set - require.Zero(t, template.MaxTTLMillis) + require.Zero(t, template.DefaultTTLMillis) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) // When: we create a workspace with autostop not enabled @@ -260,15 +260,15 @@ func TestPostWorkspacesByOrganization(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) templateTTL := 24 * time.Hour.Milliseconds() template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { - ctr.MaxTTLMillis = ptr.Ref(templateTTL) + ctr.DefaultTTLMillis = ptr.Ref(templateTTL) }) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { cwr.TTLMillis = nil // ensure that no default TTL is set }) // TTL should be set by the template - require.Equal(t, template.MaxTTLMillis, templateTTL) - require.Equal(t, template.MaxTTLMillis, template.MaxTTLMillis, workspace.TTLMillis) + require.Equal(t, template.DefaultTTLMillis, templateTTL) + require.Equal(t, template.DefaultTTLMillis, template.DefaultTTLMillis, workspace.TTLMillis) }) t.Run("InvalidTTL", func(t *testing.T) { @@ -313,7 +313,7 @@ func TestPostWorkspacesByOrganization(t *testing.T) { req := codersdk.CreateWorkspaceRequest{ TemplateID: template.ID, Name: "testing", - TTLMillis: ptr.Ref(template.MaxTTLMillis + time.Minute.Milliseconds()), + TTLMillis: ptr.Ref(template.DefaultTTLMillis + time.Minute.Milliseconds()), } _, err := client.CreateWorkspace(ctx, template.OrganizationID, codersdk.Me, req) require.Error(t, err) @@ -1162,21 +1162,23 @@ func TestWorkspaceUpdateTTL(t *testing.T) { expectedError: "time until shutdown must be less than 7 days", }, { - name: "above template maximum ttl", - ttlMillis: ptr.Ref((12 * time.Hour).Milliseconds()), - expectedError: "ttl_ms: time until shutdown must be below template maximum 8h0m0s", - modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { ctr.MaxTTLMillis = ptr.Ref((8 * time.Hour).Milliseconds()) }, + name: "above template maximum ttl", + ttlMillis: ptr.Ref((12 * time.Hour).Milliseconds()), + expectedError: "ttl_ms: time until shutdown must be below template maximum 8h0m0s", + modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { + ctr.DefaultTTLMillis = ptr.Ref((8 * time.Hour).Milliseconds()) + }, }, { name: "no template maximum ttl", ttlMillis: ptr.Ref((7 * 24 * time.Hour).Milliseconds()), - modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { ctr.MaxTTLMillis = ptr.Ref(int64(0)) }, + modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { ctr.DefaultTTLMillis = ptr.Ref(int64(0)) }, }, { name: "above maximum ttl even with no template max", ttlMillis: ptr.Ref((365 * 24 * time.Hour).Milliseconds()), expectedError: "ttl_ms: time until shutdown must be less than 7 days", - modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { ctr.MaxTTLMillis = ptr.Ref(int64(0)) }, + modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { ctr.DefaultTTLMillis = ptr.Ref(int64(0)) }, }, } @@ -1297,7 +1299,7 @@ func TestWorkspaceExtend(t *testing.T) { 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) + deadlineExceedsMaxTTL := time.Now().Add(time.Duration(template.DefaultTTLMillis) * time.Millisecond).Add(time.Minute) err = client.PutExtendWorkspace(ctx, workspace.ID, codersdk.PutExtendWorkspaceRequest{ Deadline: deadlineExceedsMaxTTL, }) diff --git a/codersdk/organizations.go b/codersdk/organizations.go index de5e42122ce28..1cb0ca5f975e2 100644 --- a/codersdk/organizations.go +++ b/codersdk/organizations.go @@ -66,14 +66,9 @@ type CreateTemplateRequest struct { VersionID uuid.UUID `json:"template_version_id" validate:"required"` ParameterValues []CreateParameterRequest `json:"parameter_values,omitempty"` - // MaxTTLMillis allows optionally specifying the maximum allowable TTL + // DefaultTTLMillis allows optionally specifying the default TTL // for all workspaces created from this template. - MaxTTLMillis *int64 `json:"max_ttl_ms,omitempty"` - - // MinAutostartIntervalMillis allows optionally specifying the minimum - // allowable duration between autostarts for all workspaces created from - // this template. - MinAutostartIntervalMillis *int64 `json:"min_autostart_interval_ms,omitempty"` + DefaultTTLMillis *int64 `json:"default_ttl_ms,omitempty"` } // CreateWorkspaceRequest provides options for creating a new workspace. diff --git a/codersdk/templates.go b/codersdk/templates.go index 6a723a665b3ab..567a807131eb8 100644 --- a/codersdk/templates.go +++ b/codersdk/templates.go @@ -27,7 +27,7 @@ type Template struct { BuildTimeStats TemplateBuildTimeStats `json:"build_time_stats"` Description string `json:"description"` Icon string `json:"icon"` - MaxTTLMillis int64 `json:"max_ttl_ms"` + DefaultTTLMillis int64 `json:"default_ttl_ms"` MinAutostartIntervalMillis int64 `json:"min_autostart_interval_ms"` CreatedByID uuid.UUID `json:"created_by_id"` CreatedByName string `json:"created_by_name"` @@ -72,10 +72,10 @@ type UpdateTemplateACL struct { } type UpdateTemplateMeta struct { - Name string `json:"name,omitempty" validate:"omitempty,username"` - Description string `json:"description,omitempty"` - Icon string `json:"icon,omitempty"` - MaxTTLMillis int64 `json:"max_ttl_ms,omitempty"` + Name string `json:"name,omitempty" validate:"omitempty,username"` + Description string `json:"description,omitempty"` + Icon string `json:"icon,omitempty"` + DefaultTTLMillis int64 `json:"default_ttl_ms,omitempty"` } // Template returns a single template. diff --git a/enterprise/audit/diff_internal_test.go b/enterprise/audit/diff_internal_test.go index ea4bab2fff7c0..e257c9606c342 100644 --- a/enterprise/audit/diff_internal_test.go +++ b/enterprise/audit/diff_internal_test.go @@ -250,7 +250,7 @@ func Test_diff(t *testing.T) { Name: "rust", Provisioner: database.ProvisionerTypeTerraform, ActiveVersionID: uuid.UUID{3}, - MaxTtl: int64(time.Hour), + DefaultTtl: int64(time.Hour), CreatedBy: uuid.UUID{4}, }, exp: audit.Map{ From f1039526fd78d30afed9397bafade6a26972e1d6 Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 1 Nov 2022 20:13:36 +0000 Subject: [PATCH 07/18] make gen --- site/src/api/typesGenerated.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 59796976b3ab1..b36e458d6443f 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -179,8 +179,7 @@ export interface CreateTemplateRequest { readonly icon?: string readonly template_version_id: string readonly parameter_values?: CreateParameterRequest[] - readonly max_ttl_ms?: number - readonly min_autostart_interval_ms?: number + readonly default_ttl_ms?: number } // From codersdk/templateversions.go @@ -620,7 +619,7 @@ export interface Template { readonly build_time_stats: TemplateBuildTimeStats readonly description: string readonly icon: string - readonly max_ttl_ms: number + readonly default_ttl_ms: number readonly min_autostart_interval_ms: number readonly created_by_id: string readonly created_by_name: string @@ -700,7 +699,7 @@ export interface UpdateTemplateMeta { readonly name?: string readonly description?: string readonly icon?: string - readonly max_ttl_ms?: number + readonly default_ttl_ms?: number } // From codersdk/users.go From 6291976472add0938e4d22257bde1dc993c4466a Mon Sep 17 00:00:00 2001 From: Garrett Date: Wed, 2 Nov 2022 15:35:28 +0000 Subject: [PATCH 08/18] more tests --- coderd/templates.go | 29 +++----------- coderd/templates_test.go | 52 ++------------------------ coderd/workspaces.go | 16 +------- coderd/workspaces_test.go | 34 ----------------- enterprise/audit/diff_internal_test.go | 2 +- enterprise/audit/table.go | 2 +- 6 files changed, 13 insertions(+), 122 deletions(-) diff --git a/coderd/templates.go b/coderd/templates.go index 1703884bf35f9..8becfd31c04df 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -25,10 +25,6 @@ import ( "github.com/coder/coder/codersdk" ) -var ( - defaultTTL = 24 * 7 * time.Hour -) - // Auto-importable templates. These can be auto-imported after the first user // has been created. type AutoImportTemplate string @@ -210,25 +206,15 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque return } - maxTTL := defaultTTL + var ttl time.Duration if createTemplate.DefaultTTLMillis != nil { - maxTTL = time.Duration(*createTemplate.DefaultTTLMillis) * time.Millisecond + ttl = time.Duration(*createTemplate.DefaultTTLMillis) * time.Millisecond } - if maxTTL < 0 { + if ttl < 0 { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid create template request.", Validations: []codersdk.ValidationError{ - {Field: "max_ttl_ms", Detail: "Must be a positive integer."}, - }, - }) - return - } - - if maxTTL > defaultTTL { - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Invalid create template request.", - Validations: []codersdk.ValidationError{ - {Field: "max_ttl_ms", Detail: "Cannot be greater than " + defaultTTL.String()}, + {Field: "default_ttl_ms", Detail: "Must be a positive integer."}, }, }) return @@ -247,7 +233,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque Provisioner: importJob.Provisioner, ActiveVersionID: templateVersion.ID, Description: createTemplate.Description, - DefaultTtl: int64(maxTTL), + DefaultTtl: int64(ttl), CreatedBy: apiKey.UserID, UserACL: database.TemplateACL{}, GroupACL: database.TemplateACL{ @@ -459,9 +445,6 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) { if req.DefaultTTLMillis < 0 { validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."}) } - if req.DefaultTTLMillis > defaultTTL.Milliseconds() { - validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Cannot be greater than " + defaultTTL.String()}) - } if len(validErrs) > 0 { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ @@ -657,7 +640,7 @@ func (api *API) autoImportTemplate(ctx context.Context, opts autoImportTemplateO Provisioner: job.Provisioner, ActiveVersionID: templateVersion.ID, Description: "This template was auto-imported by Coder.", - DefaultTtl: int64(defaultTTL), + DefaultTtl: 0, CreatedBy: opts.userID, UserACL: database.TemplateACL{}, GroupACL: database.TemplateACL{ diff --git a/coderd/templates_test.go b/coderd/templates_test.go index d66cd4fb47b6e..110c6bcba445d 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -138,27 +138,7 @@ func TestPostTemplateByOrganization(t *testing.T) { var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) - require.Contains(t, err.Error(), "max_ttl_ms: Must be a positive integer") - }) - - t.Run("MaxTTLTooHigh", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t, nil) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - _, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{ - Name: "testing", - VersionID: version.ID, - DefaultTTLMillis: ptr.Ref(365 * 24 * time.Hour.Milliseconds()), - }) - var apiErr *codersdk.Error - require.ErrorAs(t, err, &apiErr) - require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) - require.Contains(t, err.Error(), "max_ttl_ms: Cannot be greater than") + require.Contains(t, err.Error(), "default_ttl_ms: Must be a positive integer") }) t.Run("NoMaxTTL", func(t *testing.T) { @@ -388,33 +368,7 @@ func TestPatchTemplateMeta(t *testing.T) { defer cancel() _, err := client.UpdateTemplateMeta(ctx, template.ID, req) - require.ErrorContains(t, err, "max_ttl_ms: Must be a positive integer") - - // Ensure no update occurred - updated, err := client.Template(ctx, template.ID) - require.NoError(t, err) - assert.Equal(t, updated.UpdatedAt, template.UpdatedAt) - assert.Equal(t, updated.DefaultTTLMillis, template.DefaultTTLMillis) - }) - - t.Run("MaxTTLTooHigh", func(t *testing.T) { - t.Parallel() - - client := coderdtest.New(t, nil) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { - ctr.DefaultTTLMillis = ptr.Ref(24 * time.Hour.Milliseconds()) - }) - req := codersdk.UpdateTemplateMeta{ - DefaultTTLMillis: 365 * 24 * time.Hour.Milliseconds(), - } - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - _, err := client.UpdateTemplateMeta(ctx, template.ID, req) - require.ErrorContains(t, err, "max_ttl_ms: Cannot be greater than") + require.ErrorContains(t, err, "default_ttl_ms: Must be a positive integer") // Ensure no update occurred updated, err := client.Template(ctx, template.ID) @@ -478,7 +432,7 @@ func TestPatchTemplateMeta(t *testing.T) { require.ErrorAs(t, err, &apiErr) require.Contains(t, apiErr.Message, "Invalid request") require.Len(t, apiErr.Validations, 1) - assert.Equal(t, apiErr.Validations[0].Field, "max_ttl_ms") + assert.Equal(t, apiErr.Validations[0].Field, "default_ttl_ms") updated, err := client.Template(ctx, template.ID) require.NoError(t, err) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 5fe0e1463c3fb..b8eabe809a6fb 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -784,13 +784,6 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) { resp := codersdk.Response{} err := api.Database.InTx(func(s database.Store) error { - template, err := s.GetTemplateByID(ctx, workspace.TemplateID) - if err != nil { - code = http.StatusInternalServerError - resp.Message = "Error fetching workspace template!" - return xerrors.Errorf("get workspace template: %w", err) - } - build, err := s.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspace.ID) if err != nil { code = http.StatusInternalServerError @@ -824,7 +817,7 @@ func (api *API) putExtendWorkspace(rw http.ResponseWriter, r *http.Request) { } newDeadline := req.Deadline.UTC() - if err := validWorkspaceDeadline(job.CompletedAt.Time, newDeadline, time.Duration(template.DefaultTtl)); err != nil { + if err := validWorkspaceDeadline(job.CompletedAt.Time, newDeadline); 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. @@ -1121,7 +1114,7 @@ func validWorkspaceTTLMillis(millis *int64, max time.Duration) (sql.NullInt64, e }, nil } -func validWorkspaceDeadline(startedAt, newDeadline time.Time, max time.Duration) error { +func validWorkspaceDeadline(startedAt, newDeadline time.Time) error { soon := time.Now().Add(29 * time.Minute) if newDeadline.Before(soon) { return errDeadlineTooSoon @@ -1132,11 +1125,6 @@ func validWorkspaceDeadline(startedAt, newDeadline time.Time, max time.Duration) return errDeadlineBeforeStart } - delta := newDeadline.Sub(startedAt) - if delta > max { - return errDeadlineOverTemplateMax - } - return nil } diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index b807037b96d05..d4c7e9b7aef76 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -298,32 +298,6 @@ func TestPostWorkspacesByOrganization(t *testing.T) { require.Equal(t, apiErr.Validations[0].Field, "ttl_ms") require.Equal(t, "time until shutdown must be at least one minute", apiErr.Validations[0].Detail) }) - - t.Run("AboveMax", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - req := codersdk.CreateWorkspaceRequest{ - TemplateID: template.ID, - Name: "testing", - TTLMillis: ptr.Ref(template.DefaultTTLMillis + time.Minute.Milliseconds()), - } - _, err := client.CreateWorkspace(ctx, template.OrganizationID, codersdk.Me, req) - require.Error(t, err) - var apiErr *codersdk.Error - require.ErrorAs(t, err, &apiErr) - require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) - require.Len(t, apiErr.Validations, 1) - require.Equal(t, apiErr.Validations[0].Field, "ttl_ms") - require.Equal(t, "time until shutdown must be less than 7 days", apiErr.Validations[0].Detail) - }) }) } @@ -1298,14 +1272,6 @@ func TestWorkspaceExtend(t *testing.T) { }) 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.DefaultTTLMillis) * time.Millisecond).Add(time.Minute) - err = client.PutExtendWorkspace(ctx, workspace.ID, codersdk.PutExtendWorkspaceRequest{ - Deadline: deadlineExceedsMaxTTL, - }) - - 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) err = client.PutExtendWorkspace(ctx, workspace.ID, codersdk.PutExtendWorkspaceRequest{ diff --git a/enterprise/audit/diff_internal_test.go b/enterprise/audit/diff_internal_test.go index e257c9606c342..226fc44b4131c 100644 --- a/enterprise/audit/diff_internal_test.go +++ b/enterprise/audit/diff_internal_test.go @@ -258,7 +258,7 @@ func Test_diff(t *testing.T) { "name": audit.OldNew{Old: "", New: "rust"}, "provisioner": audit.OldNew{Old: database.ProvisionerType(""), New: database.ProvisionerTypeTerraform}, "active_version_id": audit.OldNew{Old: "", New: uuid.UUID{3}.String()}, - "max_ttl": audit.OldNew{Old: int64(0), New: int64(time.Hour)}, + "default_ttl": audit.OldNew{Old: int64(0), New: int64(time.Hour)}, "created_by": audit.OldNew{Old: "", New: uuid.UUID{4}.String()}, }, }, diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index 2578ae7437844..72774ced4e142 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -58,7 +58,7 @@ var AuditableResources = auditMap(map[any]map[string]Action{ "active_version_id": ActionTrack, "description": ActionTrack, "icon": ActionTrack, - "max_ttl": ActionTrack, + "default_ttl": ActionTrack, "min_autostart_interval": ActionTrack, "created_by": ActionTrack, "is_private": ActionTrack, From e1ec10714a36908ea2d56b2bc43c414d9e3a9213 Mon Sep 17 00:00:00 2001 From: Garrett Date: Wed, 2 Nov 2022 15:41:24 +0000 Subject: [PATCH 09/18] drop field from sdk --- cli/templateedit_test.go | 1 - cli/templates.go | 34 ++++++++++++++++------------------ coderd/templates_test.go | 2 -- codersdk/templates.go | 15 +++++++-------- site/src/api/typesGenerated.ts | 1 - 5 files changed, 23 insertions(+), 30 deletions(-) diff --git a/cli/templateedit_test.go b/cli/templateedit_test.go index 3b66dd6d34b41..fbfc77d26fdf5 100644 --- a/cli/templateedit_test.go +++ b/cli/templateedit_test.go @@ -95,6 +95,5 @@ func TestTemplateEdit(t *testing.T) { assert.Equal(t, template.Description, updated.Description) assert.Equal(t, template.Icon, updated.Icon) assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis) - assert.Equal(t, template.MinAutostartIntervalMillis, updated.MinAutostartIntervalMillis) }) } diff --git a/cli/templates.go b/cli/templates.go index 5d96805a153f8..7f8aa7e861792 100644 --- a/cli/templates.go +++ b/cli/templates.go @@ -50,15 +50,14 @@ func templates() *cobra.Command { } type templateTableRow struct { - Name string `table:"name"` - CreatedAt string `table:"created at"` - LastUpdated string `table:"last updated"` - OrganizationID uuid.UUID `table:"organization id"` - Provisioner codersdk.ProvisionerType `table:"provisioner"` - ActiveVersionID uuid.UUID `table:"active version id"` - UsedBy string `table:"used by"` - MaxTTL time.Duration `table:"max ttl"` - MinAutostartInterval time.Duration `table:"min autostart"` + Name string `table:"name"` + CreatedAt string `table:"created at"` + LastUpdated string `table:"last updated"` + OrganizationID uuid.UUID `table:"organization id"` + Provisioner codersdk.ProvisionerType `table:"provisioner"` + ActiveVersionID uuid.UUID `table:"active version id"` + UsedBy string `table:"used by"` + DefaultTTL time.Duration `table:"default ttl"` } // displayTemplates will return a table displaying all templates passed in. @@ -68,15 +67,14 @@ func displayTemplates(filterColumns []string, templates ...codersdk.Template) (s rows := make([]templateTableRow, len(templates)) for i, template := range templates { rows[i] = templateTableRow{ - Name: template.Name, - CreatedAt: template.CreatedAt.Format("January 2, 2006"), - LastUpdated: template.UpdatedAt.Format("January 2, 2006"), - OrganizationID: template.OrganizationID, - Provisioner: template.Provisioner, - ActiveVersionID: template.ActiveVersionID, - UsedBy: cliui.Styles.Fuchsia.Render(formatActiveDevelopers(template.ActiveUserCount)), - MaxTTL: (time.Duration(template.DefaultTTLMillis) * time.Millisecond), - MinAutostartInterval: (time.Duration(template.MinAutostartIntervalMillis) * time.Millisecond), + Name: template.Name, + CreatedAt: template.CreatedAt.Format("January 2, 2006"), + LastUpdated: template.UpdatedAt.Format("January 2, 2006"), + OrganizationID: template.OrganizationID, + Provisioner: template.Provisioner, + ActiveVersionID: template.ActiveVersionID, + UsedBy: cliui.Styles.Fuchsia.Render(formatActiveDevelopers(template.ActiveUserCount)), + DefaultTTL: (time.Duration(template.DefaultTTLMillis) * time.Millisecond), } } diff --git a/coderd/templates_test.go b/coderd/templates_test.go index 110c6bcba445d..df047993b5061 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -407,7 +407,6 @@ func TestPatchTemplateMeta(t *testing.T) { assert.Equal(t, template.Description, updated.Description) assert.Equal(t, template.Icon, updated.Icon) assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis) - assert.Equal(t, template.MinAutostartIntervalMillis, updated.MinAutostartIntervalMillis) }) t.Run("Invalid", func(t *testing.T) { @@ -441,7 +440,6 @@ func TestPatchTemplateMeta(t *testing.T) { assert.Equal(t, template.Description, updated.Description) assert.Equal(t, template.Icon, updated.Icon) assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis) - assert.Equal(t, template.MinAutostartIntervalMillis, updated.MinAutostartIntervalMillis) }) t.Run("RemoveIcon", func(t *testing.T) { diff --git a/codersdk/templates.go b/codersdk/templates.go index 567a807131eb8..05e845240be8f 100644 --- a/codersdk/templates.go +++ b/codersdk/templates.go @@ -23,14 +23,13 @@ type Template struct { ActiveVersionID uuid.UUID `json:"active_version_id"` WorkspaceOwnerCount uint32 `json:"workspace_owner_count"` // ActiveUserCount is set to -1 when loading. - ActiveUserCount int `json:"active_user_count"` - BuildTimeStats TemplateBuildTimeStats `json:"build_time_stats"` - Description string `json:"description"` - Icon string `json:"icon"` - DefaultTTLMillis int64 `json:"default_ttl_ms"` - MinAutostartIntervalMillis int64 `json:"min_autostart_interval_ms"` - CreatedByID uuid.UUID `json:"created_by_id"` - CreatedByName string `json:"created_by_name"` + ActiveUserCount int `json:"active_user_count"` + BuildTimeStats TemplateBuildTimeStats `json:"build_time_stats"` + Description string `json:"description"` + Icon string `json:"icon"` + DefaultTTLMillis int64 `json:"default_ttl_ms"` + CreatedByID uuid.UUID `json:"created_by_id"` + CreatedByName string `json:"created_by_name"` } type TemplateBuildTimeStats struct { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index b36e458d6443f..bb8d4fa38c16f 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -620,7 +620,6 @@ export interface Template { readonly description: string readonly icon: string readonly default_ttl_ms: number - readonly min_autostart_interval_ms: number readonly created_by_id: string readonly created_by_name: string } From b9c9d7bc9c818f758d3ef5d9ea67dccf95f88999 Mon Sep 17 00:00:00 2001 From: Garrett Date: Wed, 2 Nov 2022 15:50:34 +0000 Subject: [PATCH 10/18] fix cli test --- cli/templatecreate_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/templatecreate_test.go b/cli/templatecreate_test.go index cca46c29ee737..98af8158241d3 100644 --- a/cli/templatecreate_test.go +++ b/cli/templatecreate_test.go @@ -52,7 +52,7 @@ func TestTemplateCreate(t *testing.T) { "my-template", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), - "--max-ttl", "24h", + "--default-ttl", "24h", } cmd, root := clitest.New(t, args...) clitest.SetupConfig(t, client, root) From a450ed87f4d2f7cc676cd726217830e9286afaab Mon Sep 17 00:00:00 2001 From: Garrett Date: Fri, 4 Nov 2022 18:58:21 +0000 Subject: [PATCH 11/18] fix migrations --- ...in_autostart.down.sql => 000070_remove_min_autostart.down.sql} | 0 ...ve_min_autostart.up.sql => 000070_remove_min_autostart.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000069_remove_min_autostart.down.sql => 000070_remove_min_autostart.down.sql} (100%) rename coderd/database/migrations/{000069_remove_min_autostart.up.sql => 000070_remove_min_autostart.up.sql} (100%) diff --git a/coderd/database/migrations/000069_remove_min_autostart.down.sql b/coderd/database/migrations/000070_remove_min_autostart.down.sql similarity index 100% rename from coderd/database/migrations/000069_remove_min_autostart.down.sql rename to coderd/database/migrations/000070_remove_min_autostart.down.sql diff --git a/coderd/database/migrations/000069_remove_min_autostart.up.sql b/coderd/database/migrations/000070_remove_min_autostart.up.sql similarity index 100% rename from coderd/database/migrations/000069_remove_min_autostart.up.sql rename to coderd/database/migrations/000070_remove_min_autostart.up.sql From 7b54fc71274b97c31d2346d01ffc71c3dcaf5233 Mon Sep 17 00:00:00 2001 From: Garrett Date: Fri, 4 Nov 2022 19:01:09 +0000 Subject: [PATCH 12/18] lint --- coderd/workspaces.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index b8eabe809a6fb..3c57cb462801d 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -37,11 +37,10 @@ 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") + 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") ) func (api *API) workspace(rw http.ResponseWriter, r *http.Request) { From a1673649759a1e1b515013be78d4c11dbb51f460 Mon Sep 17 00:00:00 2001 From: Garrett Date: Fri, 4 Nov 2022 20:10:47 +0000 Subject: [PATCH 13/18] add tests for default values --- coderd/workspaces.go | 20 ++++++++------- coderd/workspaces_test.go | 51 ++++++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 3c57cb462801d..0002c65178cc6 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -341,7 +341,7 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req return } - dbTTL, err := validWorkspaceTTLMillis(createWorkspace.TTLMillis, time.Duration(template.DefaultTtl)) + dbTTL, err := validWorkspaceTTLMillis(createWorkspace.TTLMillis, template.DefaultTtl) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid Workspace Time to Shutdown.", @@ -729,7 +729,7 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) { return xerrors.Errorf("fetch workspace template: %w", err) } - dbTTL, err = validWorkspaceTTLMillis(req.TTLMillis, time.Duration(template.DefaultTtl)) + dbTTL, err = validWorkspaceTTLMillis(req.TTLMillis, template.DefaultTtl) if err != nil { return codersdk.ValidationError{Field: "ttl_ms", Detail: err.Error()} } @@ -1087,9 +1087,16 @@ func convertWorkspaceTTLMillis(i sql.NullInt64) *int64 { return &millis } -func validWorkspaceTTLMillis(millis *int64, max time.Duration) (sql.NullInt64, error) { +func validWorkspaceTTLMillis(millis *int64, def int64) (sql.NullInt64, error) { if ptr.NilOrZero(millis) { - return sql.NullInt64{}, nil + if def == 0 { + return sql.NullInt64{}, nil + } + + return sql.NullInt64{ + Int64: def, + Valid: true, + }, nil } dur := time.Duration(*millis) * time.Millisecond @@ -1102,11 +1109,6 @@ func validWorkspaceTTLMillis(millis *int64, max time.Duration) (sql.NullInt64, e return sql.NullInt64{}, errTTLMax } - // template level - if max > 0 && truncated > max { - return sql.NullInt64{}, xerrors.Errorf("time until shutdown must be below template maximum %s", max.String()) - } - return sql.NullInt64{ Valid: true, Int64: int64(truncated), diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index d4c7e9b7aef76..bc8a6b05664cb 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -299,6 +299,38 @@ func TestPostWorkspacesByOrganization(t *testing.T) { require.Equal(t, "time until shutdown must be at least one minute", apiErr.Validations[0].Detail) }) }) + + t.Run("TemplateDefaultTTL", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + exp := 24 * time.Hour.Milliseconds() + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { + ctr.DefaultTTLMillis = &exp + }) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + // no TTL provided should use template default + req := codersdk.CreateWorkspaceRequest{ + TemplateID: template.ID, + Name: "testing", + } + ws, err := client.CreateWorkspace(ctx, template.OrganizationID, codersdk.Me, req) + require.NoError(t, err) + require.EqualValues(t, exp, *ws.TTLMillis) + + // TTL provided should override template default + req.Name = "testing2" + exp = 1 * time.Hour.Milliseconds() + req.TTLMillis = &exp + ws, err = client.CreateWorkspace(ctx, template.OrganizationID, codersdk.Me, req) + require.NoError(t, err) + require.EqualValues(t, exp, *ws.TTLMillis) + }) } func TestWorkspaceByOwnerAndName(t *testing.T) { @@ -1135,25 +1167,6 @@ func TestWorkspaceUpdateTTL(t *testing.T) { ttlMillis: ptr.Ref((24*7*time.Hour + time.Minute).Milliseconds()), expectedError: "time until shutdown must be less than 7 days", }, - { - name: "above template maximum ttl", - ttlMillis: ptr.Ref((12 * time.Hour).Milliseconds()), - expectedError: "ttl_ms: time until shutdown must be below template maximum 8h0m0s", - modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { - ctr.DefaultTTLMillis = ptr.Ref((8 * time.Hour).Milliseconds()) - }, - }, - { - name: "no template maximum ttl", - ttlMillis: ptr.Ref((7 * 24 * time.Hour).Milliseconds()), - modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { ctr.DefaultTTLMillis = ptr.Ref(int64(0)) }, - }, - { - name: "above maximum ttl even with no template max", - ttlMillis: ptr.Ref((365 * 24 * time.Hour).Milliseconds()), - expectedError: "ttl_ms: time until shutdown must be less than 7 days", - modifyTemplate: func(ctr *codersdk.CreateTemplateRequest) { ctr.DefaultTTLMillis = ptr.Ref(int64(0)) }, - }, } for _, testCase := range testCases { From 323bddd52092abbf18afe827769322b996e57f2d Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 7 Nov 2022 17:35:39 +0000 Subject: [PATCH 14/18] fix migration --- ...in_autostart.down.sql => 000072_remove_min_autostart.down.sql} | 0 ...ve_min_autostart.up.sql => 000072_remove_min_autostart.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000070_remove_min_autostart.down.sql => 000072_remove_min_autostart.down.sql} (100%) rename coderd/database/migrations/{000070_remove_min_autostart.up.sql => 000072_remove_min_autostart.up.sql} (100%) diff --git a/coderd/database/migrations/000070_remove_min_autostart.down.sql b/coderd/database/migrations/000072_remove_min_autostart.down.sql similarity index 100% rename from coderd/database/migrations/000070_remove_min_autostart.down.sql rename to coderd/database/migrations/000072_remove_min_autostart.down.sql diff --git a/coderd/database/migrations/000070_remove_min_autostart.up.sql b/coderd/database/migrations/000072_remove_min_autostart.up.sql similarity index 100% rename from coderd/database/migrations/000070_remove_min_autostart.up.sql rename to coderd/database/migrations/000072_remove_min_autostart.up.sql From ef2ea57cd9bef61c00125cf22c65f79b40f3ed66 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 7 Nov 2022 21:40:20 +0000 Subject: [PATCH 15/18] change to default naing in fe --- .../TemplateSettingsForm.tsx | 22 +++++++++---------- .../TemplateSettingsPage.test.tsx | 18 +++++++-------- site/src/testHelpers/entities.ts | 2 +- site/src/util/schedule.test.ts | 8 +++---- site/src/util/schedule.ts | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/site/src/pages/TemplateSettingsPage/TemplateSettingsForm.tsx b/site/src/pages/TemplateSettingsPage/TemplateSettingsForm.tsx index 7ef9f758fc498..2b30f6fb803dc 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSettingsForm.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSettingsForm.tsx @@ -19,7 +19,7 @@ import * as Yup from "yup" export const Language = { nameLabel: "Name", descriptionLabel: "Description", - maxTtlLabel: "Auto-stop limit", + defaultTtlLabel: "Auto-stop default", iconLabel: "Icon", formAriaLabel: "Template settings form", selectEmoji: "Select emoji", @@ -28,7 +28,7 @@ export const Language = { descriptionMaxError: "Please enter a description that is less than or equal to 128 characters.", ttlHelperText: (ttl: number): string => - `Workspaces created from this template may not remain running longer than ${ttl} hours.`, + `Workspaces created from this template will default to stopping after ${ttl} hours.`, } const MAX_DESCRIPTION_CHAR_LIMIT = 128 @@ -41,7 +41,7 @@ export const validationSchema = Yup.object({ MAX_DESCRIPTION_CHAR_LIMIT, Language.descriptionMaxError, ), - max_ttl_ms: Yup.number() + default_ttl_ms: Yup.number() .integer() .min(0) .max(24 * MAX_TTL_DAYS /* 7 days in hours */, Language.ttlMaxError), @@ -72,7 +72,7 @@ export const TemplateSettingsForm: FC = ({ name: template.name, description: template.description, // on display, convert from ms => hours - max_ttl_ms: template.max_ttl_ms / MS_HOUR_CONVERSION, + default_ttl_ms: template.default_ttl_ms / MS_HOUR_CONVERSION, icon: template.icon, }, validationSchema, @@ -80,8 +80,8 @@ export const TemplateSettingsForm: FC = ({ // on submit, convert from hours => ms onSubmit({ ...formData, - max_ttl_ms: formData.max_ttl_ms - ? formData.max_ttl_ms * MS_HOUR_CONVERSION + default_ttl_ms: formData.default_ttl_ms + ? formData.default_ttl_ms * MS_HOUR_CONVERSION : undefined, }) }, @@ -176,20 +176,20 @@ export const TemplateSettingsForm: FC = ({ - {/* If a value for max_ttl_ms has been entered and + {/* If a value for default_ttl_ms has been entered and there are no validation errors for that field, display helper text. We do not use the MUI helper-text prop because it overrides the validation error */} - {form.values.max_ttl_ms && !form.errors.max_ttl_ms && ( + {form.values.default_ttl_ms && !form.errors.default_ttl_ms && ( - {Language.ttlHelperText(form.values.max_ttl_ms)} + {Language.ttlHelperText(form.values.default_ttl_ms)} )} diff --git a/site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx b/site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx index f6db0bde004d9..080a848c76238 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx @@ -26,13 +26,13 @@ const validFormValues = { name: "Name", description: "A description", icon: "A string", - max_ttl_ms: 1, + default_ttl_ms: 1, } const fillAndSubmitForm = async ({ name, description, - max_ttl_ms, + default_ttl_ms, icon, }: Omit, "min_autostart_interval_ms">) => { const nameField = await screen.findByLabelText(FormLanguage.nameLabel) @@ -49,9 +49,9 @@ const fillAndSubmitForm = async ({ await userEvent.clear(iconField) await userEvent.type(iconField, icon) - const maxTtlField = await screen.findByLabelText(FormLanguage.maxTtlLabel) + const maxTtlField = await screen.findByLabelText(FormLanguage.defaultTtlLabel) await userEvent.clear(maxTtlField) - await userEvent.type(maxTtlField, max_ttl_ms.toString()) + await userEvent.type(maxTtlField, default_ttl_ms.toString()) const submitButton = await screen.findByText( FooterFormLanguage.defaultSubmitLabel, @@ -87,7 +87,7 @@ describe("TemplateSettingsPage", () => { }) await fillAndSubmitForm(validFormValues) - expect(screen.getByDisplayValue(1)).toBeInTheDocument() // the max_ttl_ms + expect(screen.getByDisplayValue(1)).toBeInTheDocument() // the default_ttl_ms await waitFor(() => expect(API.updateTemplateMeta).toBeCalledTimes(1)) await waitFor(() => @@ -95,7 +95,7 @@ describe("TemplateSettingsPage", () => { "test-template", expect.objectContaining({ ...validFormValues, - max_ttl_ms: 3600000, // the max_ttl_ms to ms + default_ttl_ms: 3600000, // the default_ttl_ms to ms }), ), ) @@ -104,7 +104,7 @@ describe("TemplateSettingsPage", () => { it("allows a ttl of 7 days", () => { const values: UpdateTemplateMeta = { ...validFormValues, - max_ttl_ms: 24 * 7, + default_ttl_ms: 24 * 7, } const validate = () => validationSchema.validateSync(values) expect(validate).not.toThrowError() @@ -113,7 +113,7 @@ describe("TemplateSettingsPage", () => { it("allows ttl of 0", () => { const values: UpdateTemplateMeta = { ...validFormValues, - max_ttl_ms: 0, + default_ttl_ms: 0, } const validate = () => validationSchema.validateSync(values) expect(validate).not.toThrowError() @@ -122,7 +122,7 @@ describe("TemplateSettingsPage", () => { it("disallows a ttl of 7 days + 1 hour", () => { const values: UpdateTemplateMeta = { ...validFormValues, - max_ttl_ms: 24 * 7 + 1, + default_ttl_ms: 24 * 7 + 1, } const validate = () => validationSchema.validateSync(values) expect(validate).toThrowError(FormLanguage.ttlMaxError) diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 343f2dd414c12..1772d2a514553 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -198,7 +198,7 @@ export const MockTemplate: TypesGen.Template = { delete_ms: 3000, }, description: "This is a test description.", - max_ttl_ms: 24 * 60 * 60 * 1000, + default_ttl_ms: 24 * 60 * 60 * 1000, min_autostart_interval_ms: 60 * 60 * 1000, created_by_id: "test-creator-id", created_by_name: "test_creator", diff --git a/site/src/util/schedule.test.ts b/site/src/util/schedule.test.ts index 9cd3dd1b50177..452727624a4e6 100644 --- a/site/src/util/schedule.test.ts +++ b/site/src/util/schedule.test.ts @@ -52,7 +52,7 @@ describe("maxDeadline", () => { it("should be never be greater than global max deadline", () => { const template: Template = { ...Mocks.MockTemplate, - max_ttl_ms: 25 * 60 * 60 * 1000, + default_ttl_ms: 25 * 60 * 60 * 1000, } // Then: deadlineMinusDisabled should be falsy @@ -65,7 +65,7 @@ describe("maxDeadline", () => { it("should be never be greater than global max deadline", () => { const template: Template = { ...Mocks.MockTemplate, - max_ttl_ms: 4 * 60 * 60 * 1000, + default_ttl_ms: 4 * 60 * 60 * 1000, } // Then: deadlineMinusDisabled should be falsy @@ -95,7 +95,7 @@ describe("canExtendDeadline", () => { it("should be falsy if the deadline is more than the template max_ttl", () => { const tooFarAhead = dayjs().add( - dayjs.duration(Mocks.MockTemplate.max_ttl_ms, "milliseconds"), + dayjs.duration(Mocks.MockTemplate.default_ttl_ms, "milliseconds"), ) expect( canExtendDeadline(tooFarAhead, Mocks.MockWorkspace, Mocks.MockTemplate), @@ -104,7 +104,7 @@ describe("canExtendDeadline", () => { it("should be truth if the deadline is within the template max_ttl", () => { const okDeadline = dayjs().add( - dayjs.duration(Mocks.MockTemplate.max_ttl_ms / 2, "milliseconds"), + dayjs.duration(Mocks.MockTemplate.default_ttl_ms / 2, "milliseconds"), ) expect( canExtendDeadline(okDeadline, Mocks.MockWorkspace, Mocks.MockTemplate), diff --git a/site/src/util/schedule.ts b/site/src/util/schedule.ts index c96ba02daa47f..4070f8101e388 100644 --- a/site/src/util/schedule.ts +++ b/site/src/util/schedule.ts @@ -139,7 +139,7 @@ export function getMaxDeadline( } const startedAt = dayjs(ws.latest_build.updated_at) const maxTemplateDeadline = startedAt.add( - dayjs.duration(tpl.max_ttl_ms, "milliseconds"), + dayjs.duration(tpl.default_ttl_ms, "milliseconds"), ) const maxGlobalDeadline = startedAt.add(deadlineExtensionMax) return dayjs.min(maxTemplateDeadline, maxGlobalDeadline) From 0cd5b85a970a6479efa885edbd3f0a5dc84fc2ca Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 8 Nov 2022 15:48:26 +0000 Subject: [PATCH 16/18] fix js tests --- .../pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx | 2 +- site/src/testHelpers/entities.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx b/site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx index 080a848c76238..95aed343c0d01 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx @@ -34,7 +34,7 @@ const fillAndSubmitForm = async ({ description, default_ttl_ms, icon, -}: Omit, "min_autostart_interval_ms">) => { +}: Required) => { const nameField = await screen.findByLabelText(FormLanguage.nameLabel) await userEvent.clear(nameField) await userEvent.type(nameField, name) diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 1772d2a514553..69361d68b9222 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -199,7 +199,6 @@ export const MockTemplate: TypesGen.Template = { }, description: "This is a test description.", default_ttl_ms: 24 * 60 * 60 * 1000, - min_autostart_interval_ms: 60 * 60 * 1000, created_by_id: "test-creator-id", created_by_name: "test_creator", icon: "/icon/code.svg", From b622dc1295a7b44d510018c7beef7231695450f7 Mon Sep 17 00:00:00 2001 From: Garrett Date: Wed, 9 Nov 2022 18:47:13 +0000 Subject: [PATCH 17/18] pr comments --- cli/templatecreate.go | 10 ++++------ coderd/database/dump.sql | 2 ++ .../migrations/000072_remove_min_autostart.up.sql | 1 + coderd/database/models.go | 11 ++++++----- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/cli/templatecreate.go b/cli/templatecreate.go index c53316a66edff..1f8833d0c957a 100644 --- a/cli/templatecreate.go +++ b/cli/templatecreate.go @@ -24,11 +24,10 @@ import ( func templateCreate() *cobra.Command { var ( - directory string - provisioner string - parameterFile string - defaultTTL time.Duration - minAutostartInterval time.Duration + directory string + provisioner string + parameterFile string + defaultTTL time.Duration ) cmd := &cobra.Command{ Use: "create [name]", @@ -133,7 +132,6 @@ func templateCreate() *cobra.Command { cmd.Flags().StringVarP(&provisioner, "test.provisioner", "", "terraform", "Customize the provisioner backend") cmd.Flags().StringVarP(¶meterFile, "parameter-file", "", "", "Specify a file path with parameter values.") cmd.Flags().DurationVarP(&defaultTTL, "default-ttl", "", 24*time.Hour, "Specify a default TTL for workspaces created from this template.") - cmd.Flags().DurationVarP(&minAutostartInterval, "min-autostart-interval", "", time.Hour, "Specify a minimum autostart interval for workspaces created from this template.") // This is for testing! err := cmd.Flags().MarkHidden("test.provisioner") if err != nil { diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index cb62c42fae208..2b369cf167fe3 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -356,6 +356,8 @@ CREATE TABLE templates ( group_acl jsonb DEFAULT '{}'::jsonb NOT NULL ); +COMMENT ON COLUMN templates.default_ttl IS 'The default duration for auto-stop for workspaces created from this template.'; + CREATE TABLE user_links ( user_id uuid NOT NULL, login_type login_type NOT NULL, diff --git a/coderd/database/migrations/000072_remove_min_autostart.up.sql b/coderd/database/migrations/000072_remove_min_autostart.up.sql index 900e0afd59525..cc13b5f1746e6 100644 --- a/coderd/database/migrations/000072_remove_min_autostart.up.sql +++ b/coderd/database/migrations/000072_remove_min_autostart.up.sql @@ -3,3 +3,4 @@ ALTER TABLE "templates" DROP COLUMN "min_autostart_interval"; -- rename "max_ttl" to "default_ttl" on "templates" table ALTER TABLE "templates" RENAME COLUMN "max_ttl" TO "default_ttl"; +COMMENT ON COLUMN templates.default_ttl IS 'The default duration for auto-stop for workspaces created from this template.'; diff --git a/coderd/database/models.go b/coderd/database/models.go index 3d2b809b04d82..f457dede07eec 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -583,11 +583,12 @@ type Template struct { Provisioner ProvisionerType `db:"provisioner" json:"provisioner"` ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"` Description string `db:"description" json:"description"` - DefaultTtl int64 `db:"default_ttl" json:"default_ttl"` - CreatedBy uuid.UUID `db:"created_by" json:"created_by"` - Icon string `db:"icon" json:"icon"` - UserACL TemplateACL `db:"user_acl" json:"user_acl"` - GroupACL TemplateACL `db:"group_acl" json:"group_acl"` + // The default duration for auto-stop for workspaces created from this template. + DefaultTtl int64 `db:"default_ttl" json:"default_ttl"` + CreatedBy uuid.UUID `db:"created_by" json:"created_by"` + Icon string `db:"icon" json:"icon"` + UserACL TemplateACL `db:"user_acl" json:"user_acl"` + GroupACL TemplateACL `db:"group_acl" json:"group_acl"` } type TemplateVersion struct { From f243da42c40092afb3e9f1e92d111fd2a70ba4c8 Mon Sep 17 00:00:00 2001 From: Garrett Date: Wed, 9 Nov 2022 19:13:17 +0000 Subject: [PATCH 18/18] fix migration --- ...in_autostart.down.sql => 000073_remove_min_autostart.down.sql} | 0 ...ve_min_autostart.up.sql => 000073_remove_min_autostart.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000072_remove_min_autostart.down.sql => 000073_remove_min_autostart.down.sql} (100%) rename coderd/database/migrations/{000072_remove_min_autostart.up.sql => 000073_remove_min_autostart.up.sql} (100%) diff --git a/coderd/database/migrations/000072_remove_min_autostart.down.sql b/coderd/database/migrations/000073_remove_min_autostart.down.sql similarity index 100% rename from coderd/database/migrations/000072_remove_min_autostart.down.sql rename to coderd/database/migrations/000073_remove_min_autostart.down.sql diff --git a/coderd/database/migrations/000072_remove_min_autostart.up.sql b/coderd/database/migrations/000073_remove_min_autostart.up.sql similarity index 100% rename from coderd/database/migrations/000072_remove_min_autostart.up.sql rename to coderd/database/migrations/000073_remove_min_autostart.up.sql 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