Skip to content

feat: add customizable ttl_bump interval #10566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add ttl bump to template create/update
  • Loading branch information
Emyrk committed Nov 7, 2023
commit bbbff524b4e8f619613f30e4800d22d4315e922e
6 changes: 6 additions & 0 deletions coderd/database/dbmem/dbmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -824,9 +824,15 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, workspaceID uui
var ttlDur time.Duration
if workspace.Ttl.Valid {
ttlDur = time.Duration(workspace.Ttl.Int64)
if workspace.TtlBump > 0 {
ttlDur += time.Duration(workspace.TtlBump)
}
}
if !template.AllowUserAutostop {
ttlDur = time.Duration(template.DefaultTTL)
if template.DefaultTtlBump > 0 {
ttlDur += time.Duration(template.DefaultTtlBump)
}
}
if ttlDur <= 0 {
// There's no TTL set anymore, so we don't know the bump duration.
Expand Down
8 changes: 4 additions & 4 deletions coderd/database/dump.sql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions coderd/database/migrations/000169_ttl_bump.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ BEGIN;

DROP VIEW template_with_users;

ALTER TABLE templates ADD COLUMN default_ttl_bump bigint DEFAULT '-1'::bigint NOT NULL;
COMMENT ON COLUMN templates.default_ttl_bump IS 'Amount of time to bump workspace ttl from activity. Anything <0 will default to the ttl time.';
ALTER TABLE templates ADD COLUMN default_ttl_bump bigint DEFAULT '0'::bigint NOT NULL;
COMMENT ON COLUMN templates.default_ttl_bump IS 'Amount of time to bump workspace ttl from activity. 0 will default to the "default_ttl" as the bump interval.';


ALTER TABLE workspaces ADD COLUMN ttl_bump bigint DEFAULT '-1'::bigint NOT NULL;
COMMENT ON COLUMN workspaces.ttl_bump IS 'Amount of time to bump workspace ttl from activity. Anything <0 will default to the ttl time.';
ALTER TABLE workspaces ADD COLUMN ttl_bump bigint DEFAULT '0'::bigint NOT NULL;
COMMENT ON COLUMN workspaces.ttl_bump IS 'Amount of time to bump workspace ttl from activity. 0 will default to the "ttl" as the bump interval.';

CREATE VIEW
template_with_users
Expand Down
4 changes: 2 additions & 2 deletions coderd/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion coderd/database/queries/templates.sql
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ SET
autostart_block_days_of_week = $9,
failure_ttl = $10,
time_til_dormant = $11,
time_til_dormant_autodelete = $12
time_til_dormant_autodelete = $12,
default_ttl_bump = $13
WHERE
id = $1
;
Expand Down
10 changes: 6 additions & 4 deletions coderd/schedule/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ type TemplateScheduleOptions struct {
UserAutostartEnabled bool `json:"user_autostart_enabled"`
UserAutostopEnabled bool `json:"user_autostop_enabled"`
DefaultTTL time.Duration `json:"default_ttl"`
DefaultTTLBump time.Duration `json:"default_ttl_bump"`
// TODO(@dean): remove MaxTTL once autostop_requirement is matured and the
// default
MaxTTL time.Duration `json:"max_ttl"`
Expand Down Expand Up @@ -207,17 +208,18 @@ func (*agplTemplateScheduleStore) Set(ctx context.Context, db database.Store, tp
ctx, span := tracing.StartSpan(ctx)
defer span.End()

if int64(opts.DefaultTTL) == tpl.DefaultTTL {
if int64(opts.DefaultTTL) == tpl.DefaultTTL && int64(opts.DefaultTTLBump) == tpl.DefaultTtlBump {
// Avoid updating the UpdatedAt timestamp if nothing will be changed.
return tpl, nil
}

var template database.Template
err := db.InTx(func(db database.Store) error {
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: tpl.ID,
UpdatedAt: dbtime.Now(),
DefaultTTL: int64(opts.DefaultTTL),
ID: tpl.ID,
UpdatedAt: dbtime.Now(),
DefaultTTL: int64(opts.DefaultTTL),
DefaultTtlBump: int64(opts.DefaultTTLBump),
// Don't allow changing these settings, but keep the value in the DB (to
// avoid clearing settings if the license has an issue).
MaxTTL: tpl.MaxTTL,
Expand Down
36 changes: 35 additions & 1 deletion coderd/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,8 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
}

var (
defaultTTL time.Duration
defaultTTL time.Duration
defaultTTLBump time.Duration
// TODO(@dean): remove max_ttl once autostop_requirement is ready
maxTTL time.Duration
autostopRequirementDaysOfWeek []string
Expand All @@ -236,6 +237,9 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
if createTemplate.DefaultTTLMillis != nil {
defaultTTL = time.Duration(*createTemplate.DefaultTTLMillis) * time.Millisecond
}
if createTemplate.DefaultTTLBumpMillis != nil {
defaultTTLBump = time.Duration(*createTemplate.DefaultTTLBumpMillis) * time.Millisecond
}
if createTemplate.AutostopRequirement != nil {
autostopRequirementDaysOfWeek = createTemplate.AutostopRequirement.DaysOfWeek
autostopRequirementWeeks = createTemplate.AutostopRequirement.Weeks
Expand Down Expand Up @@ -264,12 +268,18 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
if defaultTTL < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
}
if defaultTTLBump < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_bump_ms", Detail: "Must be a positive integer."})
}
if maxTTL < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."})
}
if maxTTL != 0 && defaultTTL > maxTTL {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be less than or equal to max_ttl_ms if max_ttl_ms is set."})
}
if maxTTL != 0 && defaultTTLBump > maxTTL {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_bump_ms", Detail: "Must be less than or equal to max_ttl_ms if max_ttl_ms is set."})
}
if len(autostopRequirementDaysOfWeek) > 0 {
autostopRequirementDaysOfWeekParsed, err = codersdk.WeekdaysToBitmap(autostopRequirementDaysOfWeek)
if err != nil {
Expand Down Expand Up @@ -365,6 +375,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
UserAutostartEnabled: allowUserAutostart,
UserAutostopEnabled: allowUserAutostop,
DefaultTTL: defaultTTL,
DefaultTTLBump: defaultTTLBump,
MaxTTL: maxTTL,
// Some of these values are enterprise-only, but the
// TemplateScheduleStore will handle avoiding setting them if
Expand Down Expand Up @@ -535,6 +546,13 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
return
}

// If the user does not specify a value for the default bump,
// set it to the existing value.
if req.DefaultTTLBumpMillis == nil {
ms := time.Duration(template.DefaultTtlBump).Milliseconds()
req.DefaultTTLBumpMillis = &ms
}

var (
validErrs []codersdk.ValidationError
autostopRequirementDaysOfWeekParsed uint8
Expand All @@ -543,12 +561,18 @@ 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.DefaultTTLBumpMillis != nil && *req.DefaultTTLBumpMillis < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_bump_ms", Detail: "Must be a positive integer."})
}
if req.MaxTTLMillis < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."})
}
if req.MaxTTLMillis != 0 && req.DefaultTTLMillis > req.MaxTTLMillis {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be less than or equal to max_ttl_ms if max_ttl_ms is set."})
}
if req.DefaultTTLBumpMillis != nil && req.MaxTTLMillis != 0 && *req.DefaultTTLBumpMillis > req.MaxTTLMillis {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_bump_ms", Detail: "Must be less than or equal to max_ttl_ms if max_ttl_ms is set."})
}
if req.AutostopRequirement == nil {
req.AutostopRequirement = &codersdk.TemplateAutostopRequirement{
DaysOfWeek: codersdk.BitmapToWeekdays(scheduleOpts.AutostopRequirement.DaysOfWeek),
Expand Down Expand Up @@ -608,7 +632,14 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
}

var updated database.Template

err = api.Database.InTx(func(tx database.Store) error {
defaultTTLBump := time.Duration(template.DefaultTtlBump)
// This should never be nil at this point, but we'll check anyway.
if req.DefaultTTLBumpMillis != nil {
defaultTTLBump = time.Duration(*req.DefaultTTLBumpMillis) * time.Millisecond
}

if req.Name == template.Name &&
req.Description == template.Description &&
req.DisplayName == template.DisplayName &&
Expand All @@ -617,6 +648,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
req.AllowUserAutostop == template.AllowUserAutostop &&
req.AllowUserCancelWorkspaceJobs == template.AllowUserCancelWorkspaceJobs &&
req.DefaultTTLMillis == time.Duration(template.DefaultTTL).Milliseconds() &&
defaultTTLBump == time.Duration(template.DefaultTtlBump) &&
req.MaxTTLMillis == time.Duration(template.MaxTTL).Milliseconds() &&
autostopRequirementDaysOfWeekParsed == scheduleOpts.AutostopRequirement.DaysOfWeek &&
autostartRequirementDaysOfWeekParsed == scheduleOpts.AutostartRequirement.DaysOfWeek &&
Expand Down Expand Up @@ -669,6 +701,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
timeTilDormantAutoDelete := time.Duration(req.TimeTilDormantAutoDeleteMillis) * time.Millisecond

if defaultTTL != time.Duration(template.DefaultTTL) ||
defaultTTLBump != time.Duration(template.DefaultTtlBump) ||
maxTTL != time.Duration(template.MaxTTL) ||
autostopRequirementDaysOfWeekParsed != scheduleOpts.AutostopRequirement.DaysOfWeek ||
autostartRequirementDaysOfWeekParsed != scheduleOpts.AutostartRequirement.DaysOfWeek ||
Expand All @@ -685,6 +718,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
UserAutostartEnabled: req.AllowUserAutostart,
UserAutostopEnabled: req.AllowUserAutostop,
DefaultTTL: defaultTTL,
DefaultTTLBump: defaultTTLBump,
MaxTTL: maxTTL,
AutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: autostopRequirementDaysOfWeekParsed,
Expand Down
4 changes: 4 additions & 0 deletions codersdk/organizations.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ type CreateTemplateRequest struct {
// DefaultTTLMillis allows optionally specifying the default TTL
// for all workspaces created from this template.
DefaultTTLMillis *int64 `json:"default_ttl_ms,omitempty"`
// DefaultTTLBumpMillis allows optionally specifying the default TTL
// bump based on workspace activity. If unset, the default TTL will be
// used as the bump amount.
DefaultTTLBumpMillis *int64 `json:"default_ttl_bump_ms,omitempty"`
// TODO(@dean): remove max_ttl once autostop_requirement is matured
MaxTTLMillis *int64 `json:"max_ttl_ms,omitempty"`
// AutostopRequirement allows optionally specifying the autostop requirement
Expand Down
2 changes: 2 additions & 0 deletions codersdk/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ type UpdateTemplateMeta struct {
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
DefaultTTLMillis int64 `json:"default_ttl_ms,omitempty"`
// DefaultTTLBumpMillis defaults to nil which means no change.
DefaultTTLBumpMillis *int64 `json:"default_ttl_bump_ms,omitempty"`
// TODO(@dean): remove max_ttl once autostop_requirement is matured
MaxTTLMillis int64 `json:"max_ttl_ms,omitempty"`
// AutostopRequirement and AutostartRequirement can only be set if your license
Expand Down
1 change: 1 addition & 0 deletions enterprise/coderd/schedule/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
AllowUserAutostart: opts.UserAutostartEnabled,
AllowUserAutostop: opts.UserAutostopEnabled,
DefaultTTL: int64(opts.DefaultTTL),
DefaultTtlBump: int64(opts.DefaultTTLBump),
MaxTTL: int64(opts.MaxTTL),
AutostopRequirementDaysOfWeek: int16(opts.AutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: opts.AutostopRequirement.Weeks,
Expand Down