mirror of https://github.com/coder/coder.git
feat: add template activity_bump property (#11734)
Allows template admins to configure the activity bump duration. Defaults to 1h.
This commit is contained in:
parent
fead57f304
commit
e1e352d8c1
|
@ -23,6 +23,7 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
|
||||||
description string
|
description string
|
||||||
icon string
|
icon string
|
||||||
defaultTTL time.Duration
|
defaultTTL time.Duration
|
||||||
|
activityBump time.Duration
|
||||||
maxTTL time.Duration
|
maxTTL time.Duration
|
||||||
autostopRequirementDaysOfWeek []string
|
autostopRequirementDaysOfWeek []string
|
||||||
autostopRequirementWeeks int64
|
autostopRequirementWeeks int64
|
||||||
|
@ -108,6 +109,10 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
|
||||||
defaultTTL = time.Duration(template.DefaultTTLMillis) * time.Millisecond
|
defaultTTL = time.Duration(template.DefaultTTLMillis) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !userSetOption(inv, "activity-bump") {
|
||||||
|
activityBump = time.Duration(template.ActivityBumpMillis) * time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
if !userSetOption(inv, "allow-user-autostop") {
|
if !userSetOption(inv, "allow-user-autostop") {
|
||||||
allowUserAutostop = template.AllowUserAutostop
|
allowUserAutostop = template.AllowUserAutostop
|
||||||
}
|
}
|
||||||
|
@ -168,12 +173,13 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
req := codersdk.UpdateTemplateMeta{
|
req := codersdk.UpdateTemplateMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
Description: description,
|
Description: description,
|
||||||
Icon: icon,
|
Icon: icon,
|
||||||
DefaultTTLMillis: defaultTTL.Milliseconds(),
|
DefaultTTLMillis: defaultTTL.Milliseconds(),
|
||||||
MaxTTLMillis: maxTTL.Milliseconds(),
|
ActivityBumpMillis: activityBump.Milliseconds(),
|
||||||
|
MaxTTLMillis: maxTTL.Milliseconds(),
|
||||||
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
|
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
|
||||||
DaysOfWeek: autostopRequirementDaysOfWeek,
|
DaysOfWeek: autostopRequirementDaysOfWeek,
|
||||||
Weeks: autostopRequirementWeeks,
|
Weeks: autostopRequirementWeeks,
|
||||||
|
@ -233,6 +239,11 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
|
||||||
Description: "Edit the template default time before shutdown - workspaces created from this template default to this value. Maps to \"Default autostop\" in the UI.",
|
Description: "Edit the template default time before shutdown - workspaces created from this template default to this value. Maps to \"Default autostop\" in the UI.",
|
||||||
Value: clibase.DurationOf(&defaultTTL),
|
Value: clibase.DurationOf(&defaultTTL),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Flag: "activity-bump",
|
||||||
|
Description: "Edit the template activity bump - workspaces created from this template will have their shutdown time bumped by this value when activity is detected. Maps to \"Activity bump\" in the UI.",
|
||||||
|
Value: clibase.DurationOf(&activityBump),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Flag: "max-ttl",
|
Flag: "max-ttl",
|
||||||
Description: "Edit the template maximum time before shutdown - workspaces created from this template must shutdown within the given duration after starting, regardless of user activity. This is an enterprise-only feature. Maps to \"Max lifetime\" in the UI.",
|
Description: "Edit the template maximum time before shutdown - workspaces created from this template must shutdown within the given duration after starting, regardless of user activity. This is an enterprise-only feature. Maps to \"Max lifetime\" in the UI.",
|
||||||
|
|
|
@ -93,6 +93,7 @@ func TestTemplateEdit(t *testing.T) {
|
||||||
"--description", template.Description,
|
"--description", template.Description,
|
||||||
"--icon", template.Icon,
|
"--icon", template.Icon,
|
||||||
"--default-ttl", (time.Duration(template.DefaultTTLMillis) * time.Millisecond).String(),
|
"--default-ttl", (time.Duration(template.DefaultTTLMillis) * time.Millisecond).String(),
|
||||||
|
"--activity-bump", (time.Duration(template.ActivityBumpMillis) * time.Millisecond).String(),
|
||||||
"--allow-user-cancel-workspace-jobs=" + strconv.FormatBool(template.AllowUserCancelWorkspaceJobs),
|
"--allow-user-cancel-workspace-jobs=" + strconv.FormatBool(template.AllowUserCancelWorkspaceJobs),
|
||||||
}
|
}
|
||||||
inv, root := clitest.New(t, cmdArgs...)
|
inv, root := clitest.New(t, cmdArgs...)
|
||||||
|
|
|
@ -6,6 +6,11 @@ USAGE:
|
||||||
Edit the metadata of a template by name.
|
Edit the metadata of a template by name.
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
|
--activity-bump duration
|
||||||
|
Edit the template activity bump - workspaces created from this
|
||||||
|
template will have their shutdown time bumped by this value when
|
||||||
|
activity is detected. Maps to "Activity bump" in the UI.
|
||||||
|
|
||||||
--allow-user-autostart bool (default: true)
|
--allow-user-autostart bool (default: true)
|
||||||
Allow users to configure autostart for workspaces on this template.
|
Allow users to configure autostart for workspaces on this template.
|
||||||
This can only be disabled in enterprise.
|
This can only be disabled in enterprise.
|
||||||
|
|
|
@ -41,6 +41,7 @@ func Test_ActivityBumpWorkspace(t *testing.T) {
|
||||||
maxDeadlineOffset *time.Duration
|
maxDeadlineOffset *time.Duration
|
||||||
workspaceTTL time.Duration
|
workspaceTTL time.Duration
|
||||||
templateTTL time.Duration
|
templateTTL time.Duration
|
||||||
|
templateActivityBump time.Duration
|
||||||
templateDisallowsUserAutostop bool
|
templateDisallowsUserAutostop bool
|
||||||
expectedBump time.Duration
|
expectedBump time.Duration
|
||||||
// If the tests get queued, we need to be able to set the next autostart
|
// If the tests get queued, we need to be able to set the next autostart
|
||||||
|
@ -137,6 +138,26 @@ func Test_ActivityBumpWorkspace(t *testing.T) {
|
||||||
expectedBump: 10*time.Hour + (time.Minute * 30),
|
expectedBump: 10*time.Hour + (time.Minute * 30),
|
||||||
nextAutostart: func(now time.Time) time.Time { return now.Add(time.Minute * 30) },
|
nextAutostart: func(now time.Time) time.Time { return now.Add(time.Minute * 30) },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Custom activity bump duration specified on the template.
|
||||||
|
name: "TemplateCustomActivityBump",
|
||||||
|
transition: database.WorkspaceTransitionStart,
|
||||||
|
jobCompletedAt: sql.NullTime{Valid: true, Time: dbtime.Now().Add(-30 * time.Minute)},
|
||||||
|
buildDeadlineOffset: ptr.Ref(-30 * time.Minute),
|
||||||
|
workspaceTTL: 8 * time.Hour,
|
||||||
|
templateActivityBump: 5 * time.Hour, // instead of default 1h
|
||||||
|
expectedBump: 5 * time.Hour,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Activity bump duration is 0.
|
||||||
|
name: "TemplateCustomActivityBumpZero",
|
||||||
|
transition: database.WorkspaceTransitionStart,
|
||||||
|
jobCompletedAt: sql.NullTime{Valid: true, Time: dbtime.Now().Add(-30 * time.Minute)},
|
||||||
|
buildDeadlineOffset: ptr.Ref(-30 * time.Minute),
|
||||||
|
workspaceTTL: 8 * time.Hour,
|
||||||
|
templateActivityBump: -1, // negative values get changed to 0 in the test
|
||||||
|
expectedBump: 0,
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
tt := tt
|
tt := tt
|
||||||
for _, tz := range timezones {
|
for _, tz := range timezones {
|
||||||
|
@ -186,11 +207,19 @@ func Test_ActivityBumpWorkspace(t *testing.T) {
|
||||||
buildID = uuid.New()
|
buildID = uuid.New()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
activityBump := 1 * time.Hour
|
||||||
|
if tt.templateActivityBump < 0 {
|
||||||
|
// less than 0 => 0
|
||||||
|
activityBump = 0
|
||||||
|
} else if tt.templateActivityBump != 0 {
|
||||||
|
activityBump = tt.templateActivityBump
|
||||||
|
}
|
||||||
require.NoError(t, db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
require.NoError(t, db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
||||||
ID: template.ID,
|
ID: template.ID,
|
||||||
UpdatedAt: dbtime.Now(),
|
UpdatedAt: dbtime.Now(),
|
||||||
AllowUserAutostop: !tt.templateDisallowsUserAutostop,
|
AllowUserAutostop: !tt.templateDisallowsUserAutostop,
|
||||||
DefaultTTL: int64(tt.templateTTL),
|
DefaultTTL: int64(tt.templateTTL),
|
||||||
|
ActivityBump: int64(activityBump),
|
||||||
}), "unexpected error updating template schedule")
|
}), "unexpected error updating template schedule")
|
||||||
|
|
||||||
var buildNumber int32 = 1
|
var buildNumber int32 = 1
|
||||||
|
|
|
@ -8536,6 +8536,10 @@ const docTemplate = `{
|
||||||
"template_version_id"
|
"template_version_id"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"activity_bump_ms": {
|
||||||
|
"description": "ActivityBumpMillis allows optionally specifying the activity bump\nduration for all workspaces created from this template. Defaults to 1h\nbut can be set to 0 to disable activity bumping.",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"allow_user_autostart": {
|
"allow_user_autostart": {
|
||||||
"description": "AllowUserAutostart allows users to set a schedule for autostarting their\nworkspace. By default this is true. This can only be disabled when using\nan enterprise license.",
|
"description": "AllowUserAutostart allows users to set a schedule for autostarting their\nworkspace. By default this is true. This can only be disabled when using\nan enterprise license.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -10954,6 +10958,9 @@ const docTemplate = `{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid"
|
"format": "uuid"
|
||||||
},
|
},
|
||||||
|
"activity_bump_ms": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"allow_user_autostart": {
|
"allow_user_autostart": {
|
||||||
"description": "AllowUserAutostart and AllowUserAutostop are enterprise-only. Their\nvalues are only used if your license is entitled to use the advanced\ntemplate scheduling feature.",
|
"description": "AllowUserAutostart and AllowUserAutostop are enterprise-only. Their\nvalues are only used if your license is entitled to use the advanced\ntemplate scheduling feature.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
|
|
@ -7609,6 +7609,10 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["name", "template_version_id"],
|
"required": ["name", "template_version_id"],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"activity_bump_ms": {
|
||||||
|
"description": "ActivityBumpMillis allows optionally specifying the activity bump\nduration for all workspaces created from this template. Defaults to 1h\nbut can be set to 0 to disable activity bumping.",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"allow_user_autostart": {
|
"allow_user_autostart": {
|
||||||
"description": "AllowUserAutostart allows users to set a schedule for autostarting their\nworkspace. By default this is true. This can only be disabled when using\nan enterprise license.",
|
"description": "AllowUserAutostart allows users to set a schedule for autostarting their\nworkspace. By default this is true. This can only be disabled when using\nan enterprise license.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -9896,6 +9900,9 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uuid"
|
"format": "uuid"
|
||||||
},
|
},
|
||||||
|
"activity_bump_ms": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"allow_user_autostart": {
|
"allow_user_autostart": {
|
||||||
"description": "AllowUserAutostart and AllowUserAutostop are enterprise-only. Their\nvalues are only used if your license is entitled to use the advanced\ntemplate scheduling feature.",
|
"description": "AllowUserAutostart and AllowUserAutostop are enterprise-only. Their\nvalues are only used if your license is entitled to use the advanced\ntemplate scheduling feature.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
|
|
@ -841,10 +841,14 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, arg database.Ac
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if template.ActivityBump == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
activityBump := time.Duration(template.ActivityBump)
|
||||||
|
|
||||||
var ttlDur time.Duration
|
var ttlDur time.Duration
|
||||||
if now.Add(time.Hour).After(arg.NextAutostart) && arg.NextAutostart.After(now) {
|
if now.Add(activityBump).After(arg.NextAutostart) && arg.NextAutostart.After(now) {
|
||||||
// Extend to TTL
|
// Extend to TTL (NOT activity bump)
|
||||||
add := arg.NextAutostart.Sub(now)
|
add := arg.NextAutostart.Sub(now)
|
||||||
if workspace.Ttl.Valid && template.AllowUserAutostop {
|
if workspace.Ttl.Valid && template.AllowUserAutostop {
|
||||||
add += time.Duration(workspace.Ttl.Int64)
|
add += time.Duration(workspace.Ttl.Int64)
|
||||||
|
@ -853,7 +857,8 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, arg database.Ac
|
||||||
}
|
}
|
||||||
ttlDur = add
|
ttlDur = add
|
||||||
} else {
|
} else {
|
||||||
ttlDur = time.Hour
|
// Otherwise, default to regular activity bump duration.
|
||||||
|
ttlDur = activityBump
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only bump if 5% of the deadline has passed.
|
// Only bump if 5% of the deadline has passed.
|
||||||
|
@ -6543,6 +6548,7 @@ func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database
|
||||||
tpl.AllowUserAutostop = arg.AllowUserAutostop
|
tpl.AllowUserAutostop = arg.AllowUserAutostop
|
||||||
tpl.UpdatedAt = dbtime.Now()
|
tpl.UpdatedAt = dbtime.Now()
|
||||||
tpl.DefaultTTL = arg.DefaultTTL
|
tpl.DefaultTTL = arg.DefaultTTL
|
||||||
|
tpl.ActivityBump = arg.ActivityBump
|
||||||
tpl.UseMaxTtl = arg.UseMaxTtl
|
tpl.UseMaxTtl = arg.UseMaxTtl
|
||||||
tpl.MaxTTL = arg.MaxTTL
|
tpl.MaxTTL = arg.MaxTTL
|
||||||
tpl.AutostopRequirementDaysOfWeek = arg.AutostopRequirementDaysOfWeek
|
tpl.AutostopRequirementDaysOfWeek = arg.AutostopRequirementDaysOfWeek
|
||||||
|
|
|
@ -849,7 +849,8 @@ CREATE TABLE templates (
|
||||||
autostart_block_days_of_week smallint DEFAULT 0 NOT NULL,
|
autostart_block_days_of_week smallint DEFAULT 0 NOT NULL,
|
||||||
require_active_version boolean DEFAULT false NOT NULL,
|
require_active_version boolean DEFAULT false NOT NULL,
|
||||||
deprecated text DEFAULT ''::text NOT NULL,
|
deprecated text DEFAULT ''::text NOT NULL,
|
||||||
use_max_ttl boolean DEFAULT false NOT NULL
|
use_max_ttl boolean DEFAULT false NOT NULL,
|
||||||
|
activity_bump bigint DEFAULT '3600000000000'::bigint NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
COMMENT ON COLUMN templates.default_ttl IS 'The default duration for autostop for workspaces created from this template.';
|
COMMENT ON COLUMN templates.default_ttl IS 'The default duration for autostop for workspaces created from this template.';
|
||||||
|
@ -899,6 +900,7 @@ CREATE VIEW template_with_users AS
|
||||||
templates.require_active_version,
|
templates.require_active_version,
|
||||||
templates.deprecated,
|
templates.deprecated,
|
||||||
templates.use_max_ttl,
|
templates.use_max_ttl,
|
||||||
|
templates.activity_bump,
|
||||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||||
COALESCE(visible_users.username, ''::text) AS created_by_username
|
COALESCE(visible_users.username, ''::text) AS created_by_username
|
||||||
FROM (public.templates
|
FROM (public.templates
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
DROP VIEW template_with_users;
|
||||||
|
|
||||||
|
ALTER TABLE templates DROP COLUMN activity_bump;
|
||||||
|
|
||||||
|
CREATE VIEW
|
||||||
|
template_with_users
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
templates.*,
|
||||||
|
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
|
||||||
|
coalesce(visible_users.username, '') AS created_by_username
|
||||||
|
FROM
|
||||||
|
templates
|
||||||
|
LEFT JOIN
|
||||||
|
visible_users
|
||||||
|
ON
|
||||||
|
templates.created_by = visible_users.id;
|
||||||
|
|
||||||
|
COMMENT ON VIEW template_with_users IS 'Joins in the username + avatar url of the created by user.';
|
|
@ -0,0 +1,19 @@
|
||||||
|
ALTER TABLE templates ADD COLUMN activity_bump bigint DEFAULT '3600000000000'::bigint NOT NULL; -- 1 hour
|
||||||
|
|
||||||
|
DROP VIEW template_with_users;
|
||||||
|
|
||||||
|
CREATE VIEW
|
||||||
|
template_with_users
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
templates.*,
|
||||||
|
coalesce(visible_users.avatar_url, '') AS created_by_avatar_url,
|
||||||
|
coalesce(visible_users.username, '') AS created_by_username
|
||||||
|
FROM
|
||||||
|
templates
|
||||||
|
LEFT JOIN
|
||||||
|
visible_users
|
||||||
|
ON
|
||||||
|
templates.created_by = visible_users.id;
|
||||||
|
|
||||||
|
COMMENT ON VIEW template_with_users IS 'Joins in the username + avatar url of the created by user.';
|
|
@ -90,6 +90,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||||
&i.RequireActiveVersion,
|
&i.RequireActiveVersion,
|
||||||
&i.Deprecated,
|
&i.Deprecated,
|
||||||
&i.UseMaxTtl,
|
&i.UseMaxTtl,
|
||||||
|
&i.ActivityBump,
|
||||||
&i.CreatedByAvatarURL,
|
&i.CreatedByAvatarURL,
|
||||||
&i.CreatedByUsername,
|
&i.CreatedByUsername,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
|
@ -2003,6 +2003,7 @@ type Template struct {
|
||||||
RequireActiveVersion bool `db:"require_active_version" json:"require_active_version"`
|
RequireActiveVersion bool `db:"require_active_version" json:"require_active_version"`
|
||||||
Deprecated string `db:"deprecated" json:"deprecated"`
|
Deprecated string `db:"deprecated" json:"deprecated"`
|
||||||
UseMaxTtl bool `db:"use_max_ttl" json:"use_max_ttl"`
|
UseMaxTtl bool `db:"use_max_ttl" json:"use_max_ttl"`
|
||||||
|
ActivityBump int64 `db:"activity_bump" json:"activity_bump"`
|
||||||
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
|
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
|
||||||
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
|
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
|
||||||
}
|
}
|
||||||
|
@ -2043,8 +2044,9 @@ type TemplateTable struct {
|
||||||
AutostartBlockDaysOfWeek int16 `db:"autostart_block_days_of_week" json:"autostart_block_days_of_week"`
|
AutostartBlockDaysOfWeek int16 `db:"autostart_block_days_of_week" json:"autostart_block_days_of_week"`
|
||||||
RequireActiveVersion bool `db:"require_active_version" json:"require_active_version"`
|
RequireActiveVersion bool `db:"require_active_version" json:"require_active_version"`
|
||||||
// If set to a non empty string, the template will no longer be able to be used. The message will be displayed to the user.
|
// If set to a non empty string, the template will no longer be able to be used. The message will be displayed to the user.
|
||||||
Deprecated string `db:"deprecated" json:"deprecated"`
|
Deprecated string `db:"deprecated" json:"deprecated"`
|
||||||
UseMaxTtl bool `db:"use_max_ttl" json:"use_max_ttl"`
|
UseMaxTtl bool `db:"use_max_ttl" json:"use_max_ttl"`
|
||||||
|
ActivityBump int64 `db:"activity_bump" json:"activity_bump"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Joins in the username + avatar url of the created by user.
|
// Joins in the username + avatar url of the created by user.
|
||||||
|
|
|
@ -24,12 +24,14 @@ type sqlcQuerier interface {
|
||||||
// multiple provisioners from acquiring the same jobs. See:
|
// multiple provisioners from acquiring the same jobs. See:
|
||||||
// https://www.postgresql.org/docs/9.5/sql-select.html#SQL-FOR-UPDATE-SHARE
|
// https://www.postgresql.org/docs/9.5/sql-select.html#SQL-FOR-UPDATE-SHARE
|
||||||
AcquireProvisionerJob(ctx context.Context, arg AcquireProvisionerJobParams) (ProvisionerJob, error)
|
AcquireProvisionerJob(ctx context.Context, arg AcquireProvisionerJobParams) (ProvisionerJob, error)
|
||||||
// Bumps the workspace deadline by 1 hour. If the workspace bump will
|
// Bumps the workspace deadline by the template's configured "activity_bump"
|
||||||
// cross an autostart threshold, then the bump is autostart + TTL. This
|
// duration (default 1h). If the workspace bump will cross an autostart
|
||||||
// is the deadline behavior if the workspace was to autostart from a stopped
|
// threshold, then the bump is autostart + TTL. This is the deadline behavior if
|
||||||
// state.
|
// the workspace was to autostart from a stopped state.
|
||||||
// Max deadline is respected, and will never be bumped.
|
//
|
||||||
|
// Max deadline is respected, and the deadline will never be bumped past it.
|
||||||
// The deadline will never decrease.
|
// The deadline will never decrease.
|
||||||
|
// We only bump if the template has an activity bump duration set.
|
||||||
// We only bump if the raw interval is positive and non-zero.
|
// We only bump if the raw interval is positive and non-zero.
|
||||||
// We only bump if workspace shutdown is manual.
|
// We only bump if workspace shutdown is manual.
|
||||||
// We only bump when 5% of the deadline has elapsed.
|
// We only bump when 5% of the deadline has elapsed.
|
||||||
|
|
|
@ -23,14 +23,19 @@ WITH latest AS (
|
||||||
workspace_builds.max_deadline::timestamp with time zone AS build_max_deadline,
|
workspace_builds.max_deadline::timestamp with time zone AS build_max_deadline,
|
||||||
workspace_builds.transition AS build_transition,
|
workspace_builds.transition AS build_transition,
|
||||||
provisioner_jobs.completed_at::timestamp with time zone AS job_completed_at,
|
provisioner_jobs.completed_at::timestamp with time zone AS job_completed_at,
|
||||||
|
templates.activity_bump AS activity_bump,
|
||||||
(
|
(
|
||||||
CASE
|
CASE
|
||||||
-- If the extension would push us over the next_autostart
|
-- If the extension would push us over the next_autostart
|
||||||
-- interval, then extend the deadline by the full ttl from
|
-- interval, then extend the deadline by the full TTL (NOT
|
||||||
-- the autostart time. This will essentially be as if the
|
-- activity bump) from the autostart time. This will essentially
|
||||||
-- workspace auto started at the given time and the original
|
-- be as if the workspace auto started at the given time and the
|
||||||
-- TTL was applied.
|
-- original TTL was applied.
|
||||||
WHEN NOW() + ('60 minutes')::interval > $1 :: timestamptz
|
--
|
||||||
|
-- Sadly we can't define ` + "`" + `activity_bump_interval` + "`" + ` above since
|
||||||
|
-- it won't be available for this CASE statement, so we have to
|
||||||
|
-- copy the cast twice.
|
||||||
|
WHEN NOW() + (templates.activity_bump / 1000 / 1000 / 1000 || ' seconds')::interval > $1 :: timestamptz
|
||||||
-- If the autostart is behind now(), then the
|
-- If the autostart is behind now(), then the
|
||||||
-- autostart schedule is either the 0 time and not provided,
|
-- autostart schedule is either the 0 time and not provided,
|
||||||
-- or it was the autostart in the past, which is no longer
|
-- or it was the autostart in the past, which is no longer
|
||||||
|
@ -38,16 +43,16 @@ WITH latest AS (
|
||||||
-- that is a mistake by the caller.
|
-- that is a mistake by the caller.
|
||||||
AND $1 > NOW()
|
AND $1 > NOW()
|
||||||
THEN
|
THEN
|
||||||
-- Extend to the autostart, then add the TTL
|
-- Extend to the autostart, then add the activity bump
|
||||||
(($1 :: timestamptz) - NOW()) + CASE
|
(($1 :: timestamptz) - NOW()) + CASE
|
||||||
WHEN templates.allow_user_autostop
|
WHEN templates.allow_user_autostop
|
||||||
THEN (workspaces.ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
THEN (workspaces.ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||||
ELSE (templates.default_ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
ELSE (templates.default_ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||||
END
|
END
|
||||||
|
|
||||||
-- Default to 60 minutes.
|
-- Default to the activity bump duration.
|
||||||
ELSE
|
ELSE
|
||||||
('60 minutes')::interval
|
(templates.activity_bump / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||||
END
|
END
|
||||||
) AS ttl_interval
|
) AS ttl_interval
|
||||||
FROM workspace_builds
|
FROM workspace_builds
|
||||||
|
@ -74,6 +79,7 @@ SET
|
||||||
FROM latest l
|
FROM latest l
|
||||||
WHERE wb.id = l.build_id
|
WHERE wb.id = l.build_id
|
||||||
AND l.job_completed_at IS NOT NULL
|
AND l.job_completed_at IS NOT NULL
|
||||||
|
AND l.activity_bump > 0
|
||||||
AND l.build_transition = 'start'
|
AND l.build_transition = 'start'
|
||||||
AND l.ttl_interval > '0 seconds'::interval
|
AND l.ttl_interval > '0 seconds'::interval
|
||||||
AND l.build_deadline != '0001-01-01 00:00:00+00'
|
AND l.build_deadline != '0001-01-01 00:00:00+00'
|
||||||
|
@ -85,12 +91,14 @@ type ActivityBumpWorkspaceParams struct {
|
||||||
WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"`
|
WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bumps the workspace deadline by 1 hour. If the workspace bump will
|
// Bumps the workspace deadline by the template's configured "activity_bump"
|
||||||
// cross an autostart threshold, then the bump is autostart + TTL. This
|
// duration (default 1h). If the workspace bump will cross an autostart
|
||||||
// is the deadline behavior if the workspace was to autostart from a stopped
|
// threshold, then the bump is autostart + TTL. This is the deadline behavior if
|
||||||
// state.
|
// the workspace was to autostart from a stopped state.
|
||||||
// Max deadline is respected, and will never be bumped.
|
//
|
||||||
|
// Max deadline is respected, and the deadline will never be bumped past it.
|
||||||
// The deadline will never decrease.
|
// The deadline will never decrease.
|
||||||
|
// We only bump if the template has an activity bump duration set.
|
||||||
// We only bump if the raw interval is positive and non-zero.
|
// We only bump if the raw interval is positive and non-zero.
|
||||||
// We only bump if workspace shutdown is manual.
|
// We only bump if workspace shutdown is manual.
|
||||||
// We only bump when 5% of the deadline has elapsed.
|
// We only bump when 5% of the deadline has elapsed.
|
||||||
|
@ -5720,7 +5728,7 @@ func (q *sqlQuerier) GetTemplateAverageBuildTime(ctx context.Context, arg GetTem
|
||||||
|
|
||||||
const getTemplateByID = `-- name: GetTemplateByID :one
|
const getTemplateByID = `-- name: GetTemplateByID :one
|
||||||
SELECT
|
SELECT
|
||||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, created_by_avatar_url, created_by_username
|
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, activity_bump, created_by_avatar_url, created_by_username
|
||||||
FROM
|
FROM
|
||||||
template_with_users
|
template_with_users
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -5761,6 +5769,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||||
&i.RequireActiveVersion,
|
&i.RequireActiveVersion,
|
||||||
&i.Deprecated,
|
&i.Deprecated,
|
||||||
&i.UseMaxTtl,
|
&i.UseMaxTtl,
|
||||||
|
&i.ActivityBump,
|
||||||
&i.CreatedByAvatarURL,
|
&i.CreatedByAvatarURL,
|
||||||
&i.CreatedByUsername,
|
&i.CreatedByUsername,
|
||||||
)
|
)
|
||||||
|
@ -5769,7 +5778,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||||
|
|
||||||
const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one
|
const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one
|
||||||
SELECT
|
SELECT
|
||||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, created_by_avatar_url, created_by_username
|
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, activity_bump, created_by_avatar_url, created_by_username
|
||||||
FROM
|
FROM
|
||||||
template_with_users AS templates
|
template_with_users AS templates
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -5818,6 +5827,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||||
&i.RequireActiveVersion,
|
&i.RequireActiveVersion,
|
||||||
&i.Deprecated,
|
&i.Deprecated,
|
||||||
&i.UseMaxTtl,
|
&i.UseMaxTtl,
|
||||||
|
&i.ActivityBump,
|
||||||
&i.CreatedByAvatarURL,
|
&i.CreatedByAvatarURL,
|
||||||
&i.CreatedByUsername,
|
&i.CreatedByUsername,
|
||||||
)
|
)
|
||||||
|
@ -5825,7 +5835,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTemplates = `-- name: GetTemplates :many
|
const getTemplates = `-- name: GetTemplates :many
|
||||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, created_by_avatar_url, created_by_username FROM template_with_users AS 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, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, activity_bump, created_by_avatar_url, created_by_username FROM template_with_users AS templates
|
||||||
ORDER BY (name, id) ASC
|
ORDER BY (name, id) ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -5867,6 +5877,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||||
&i.RequireActiveVersion,
|
&i.RequireActiveVersion,
|
||||||
&i.Deprecated,
|
&i.Deprecated,
|
||||||
&i.UseMaxTtl,
|
&i.UseMaxTtl,
|
||||||
|
&i.ActivityBump,
|
||||||
&i.CreatedByAvatarURL,
|
&i.CreatedByAvatarURL,
|
||||||
&i.CreatedByUsername,
|
&i.CreatedByUsername,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
@ -5885,7 +5896,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||||
|
|
||||||
const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many
|
const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many
|
||||||
SELECT
|
SELECT
|
||||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, created_by_avatar_url, created_by_username
|
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, activity_bump, created_by_avatar_url, created_by_username
|
||||||
FROM
|
FROM
|
||||||
template_with_users AS templates
|
template_with_users AS templates
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -5977,6 +5988,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||||
&i.RequireActiveVersion,
|
&i.RequireActiveVersion,
|
||||||
&i.Deprecated,
|
&i.Deprecated,
|
||||||
&i.UseMaxTtl,
|
&i.UseMaxTtl,
|
||||||
|
&i.ActivityBump,
|
||||||
&i.CreatedByAvatarURL,
|
&i.CreatedByAvatarURL,
|
||||||
&i.CreatedByUsername,
|
&i.CreatedByUsername,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
@ -6184,14 +6196,15 @@ SET
|
||||||
allow_user_autostart = $3,
|
allow_user_autostart = $3,
|
||||||
allow_user_autostop = $4,
|
allow_user_autostop = $4,
|
||||||
default_ttl = $5,
|
default_ttl = $5,
|
||||||
use_max_ttl = $6,
|
activity_bump = $6,
|
||||||
max_ttl = $7,
|
use_max_ttl = $7,
|
||||||
autostop_requirement_days_of_week = $8,
|
max_ttl = $8,
|
||||||
autostop_requirement_weeks = $9,
|
autostop_requirement_days_of_week = $9,
|
||||||
autostart_block_days_of_week = $10,
|
autostop_requirement_weeks = $10,
|
||||||
failure_ttl = $11,
|
autostart_block_days_of_week = $11,
|
||||||
time_til_dormant = $12,
|
failure_ttl = $12,
|
||||||
time_til_dormant_autodelete = $13
|
time_til_dormant = $13,
|
||||||
|
time_til_dormant_autodelete = $14
|
||||||
WHERE
|
WHERE
|
||||||
id = $1
|
id = $1
|
||||||
`
|
`
|
||||||
|
@ -6202,6 +6215,7 @@ type UpdateTemplateScheduleByIDParams struct {
|
||||||
AllowUserAutostart bool `db:"allow_user_autostart" json:"allow_user_autostart"`
|
AllowUserAutostart bool `db:"allow_user_autostart" json:"allow_user_autostart"`
|
||||||
AllowUserAutostop bool `db:"allow_user_autostop" json:"allow_user_autostop"`
|
AllowUserAutostop bool `db:"allow_user_autostop" json:"allow_user_autostop"`
|
||||||
DefaultTTL int64 `db:"default_ttl" json:"default_ttl"`
|
DefaultTTL int64 `db:"default_ttl" json:"default_ttl"`
|
||||||
|
ActivityBump int64 `db:"activity_bump" json:"activity_bump"`
|
||||||
UseMaxTtl bool `db:"use_max_ttl" json:"use_max_ttl"`
|
UseMaxTtl bool `db:"use_max_ttl" json:"use_max_ttl"`
|
||||||
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
|
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
|
||||||
AutostopRequirementDaysOfWeek int16 `db:"autostop_requirement_days_of_week" json:"autostop_requirement_days_of_week"`
|
AutostopRequirementDaysOfWeek int16 `db:"autostop_requirement_days_of_week" json:"autostop_requirement_days_of_week"`
|
||||||
|
@ -6219,6 +6233,7 @@ func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateT
|
||||||
arg.AllowUserAutostart,
|
arg.AllowUserAutostart,
|
||||||
arg.AllowUserAutostop,
|
arg.AllowUserAutostop,
|
||||||
arg.DefaultTTL,
|
arg.DefaultTTL,
|
||||||
|
arg.ActivityBump,
|
||||||
arg.UseMaxTtl,
|
arg.UseMaxTtl,
|
||||||
arg.MaxTTL,
|
arg.MaxTTL,
|
||||||
arg.AutostopRequirementDaysOfWeek,
|
arg.AutostopRequirementDaysOfWeek,
|
||||||
|
@ -11363,7 +11378,7 @@ LEFT JOIN LATERAL (
|
||||||
) latest_build ON TRUE
|
) latest_build ON TRUE
|
||||||
LEFT JOIN LATERAL (
|
LEFT JOIN LATERAL (
|
||||||
SELECT
|
SELECT
|
||||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl
|
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, use_max_ttl, activity_bump
|
||||||
FROM
|
FROM
|
||||||
templates
|
templates
|
||||||
WHERE
|
WHERE
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
-- Bumps the workspace deadline by 1 hour. If the workspace bump will
|
-- Bumps the workspace deadline by the template's configured "activity_bump"
|
||||||
-- cross an autostart threshold, then the bump is autostart + TTL. This
|
-- duration (default 1h). If the workspace bump will cross an autostart
|
||||||
-- is the deadline behavior if the workspace was to autostart from a stopped
|
-- threshold, then the bump is autostart + TTL. This is the deadline behavior if
|
||||||
-- state.
|
-- the workspace was to autostart from a stopped state.
|
||||||
-- Max deadline is respected, and will never be bumped.
|
--
|
||||||
|
-- Max deadline is respected, and the deadline will never be bumped past it.
|
||||||
-- The deadline will never decrease.
|
-- The deadline will never decrease.
|
||||||
-- name: ActivityBumpWorkspace :exec
|
-- name: ActivityBumpWorkspace :exec
|
||||||
WITH latest AS (
|
WITH latest AS (
|
||||||
|
@ -12,14 +13,19 @@ WITH latest AS (
|
||||||
workspace_builds.max_deadline::timestamp with time zone AS build_max_deadline,
|
workspace_builds.max_deadline::timestamp with time zone AS build_max_deadline,
|
||||||
workspace_builds.transition AS build_transition,
|
workspace_builds.transition AS build_transition,
|
||||||
provisioner_jobs.completed_at::timestamp with time zone AS job_completed_at,
|
provisioner_jobs.completed_at::timestamp with time zone AS job_completed_at,
|
||||||
|
templates.activity_bump AS activity_bump,
|
||||||
(
|
(
|
||||||
CASE
|
CASE
|
||||||
-- If the extension would push us over the next_autostart
|
-- If the extension would push us over the next_autostart
|
||||||
-- interval, then extend the deadline by the full ttl from
|
-- interval, then extend the deadline by the full TTL (NOT
|
||||||
-- the autostart time. This will essentially be as if the
|
-- activity bump) from the autostart time. This will essentially
|
||||||
-- workspace auto started at the given time and the original
|
-- be as if the workspace auto started at the given time and the
|
||||||
-- TTL was applied.
|
-- original TTL was applied.
|
||||||
WHEN NOW() + ('60 minutes')::interval > @next_autostart :: timestamptz
|
--
|
||||||
|
-- Sadly we can't define `activity_bump_interval` above since
|
||||||
|
-- it won't be available for this CASE statement, so we have to
|
||||||
|
-- copy the cast twice.
|
||||||
|
WHEN NOW() + (templates.activity_bump / 1000 / 1000 / 1000 || ' seconds')::interval > @next_autostart :: timestamptz
|
||||||
-- If the autostart is behind now(), then the
|
-- If the autostart is behind now(), then the
|
||||||
-- autostart schedule is either the 0 time and not provided,
|
-- autostart schedule is either the 0 time and not provided,
|
||||||
-- or it was the autostart in the past, which is no longer
|
-- or it was the autostart in the past, which is no longer
|
||||||
|
@ -27,16 +33,16 @@ WITH latest AS (
|
||||||
-- that is a mistake by the caller.
|
-- that is a mistake by the caller.
|
||||||
AND @next_autostart > NOW()
|
AND @next_autostart > NOW()
|
||||||
THEN
|
THEN
|
||||||
-- Extend to the autostart, then add the TTL
|
-- Extend to the autostart, then add the activity bump
|
||||||
((@next_autostart :: timestamptz) - NOW()) + CASE
|
((@next_autostart :: timestamptz) - NOW()) + CASE
|
||||||
WHEN templates.allow_user_autostop
|
WHEN templates.allow_user_autostop
|
||||||
THEN (workspaces.ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
THEN (workspaces.ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||||
ELSE (templates.default_ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
ELSE (templates.default_ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||||
END
|
END
|
||||||
|
|
||||||
-- Default to 60 minutes.
|
-- Default to the activity bump duration.
|
||||||
ELSE
|
ELSE
|
||||||
('60 minutes')::interval
|
(templates.activity_bump / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||||
END
|
END
|
||||||
) AS ttl_interval
|
) AS ttl_interval
|
||||||
FROM workspace_builds
|
FROM workspace_builds
|
||||||
|
@ -63,6 +69,8 @@ SET
|
||||||
FROM latest l
|
FROM latest l
|
||||||
WHERE wb.id = l.build_id
|
WHERE wb.id = l.build_id
|
||||||
AND l.job_completed_at IS NOT NULL
|
AND l.job_completed_at IS NOT NULL
|
||||||
|
-- We only bump if the template has an activity bump duration set.
|
||||||
|
AND l.activity_bump > 0
|
||||||
AND l.build_transition = 'start'
|
AND l.build_transition = 'start'
|
||||||
-- We only bump if the raw interval is positive and non-zero.
|
-- We only bump if the raw interval is positive and non-zero.
|
||||||
AND l.ttl_interval > '0 seconds'::interval
|
AND l.ttl_interval > '0 seconds'::interval
|
||||||
|
|
|
@ -129,14 +129,15 @@ SET
|
||||||
allow_user_autostart = $3,
|
allow_user_autostart = $3,
|
||||||
allow_user_autostop = $4,
|
allow_user_autostop = $4,
|
||||||
default_ttl = $5,
|
default_ttl = $5,
|
||||||
use_max_ttl = $6,
|
activity_bump = $6,
|
||||||
max_ttl = $7,
|
use_max_ttl = $7,
|
||||||
autostop_requirement_days_of_week = $8,
|
max_ttl = $8,
|
||||||
autostop_requirement_weeks = $9,
|
autostop_requirement_days_of_week = $9,
|
||||||
autostart_block_days_of_week = $10,
|
autostop_requirement_weeks = $10,
|
||||||
failure_ttl = $11,
|
autostart_block_days_of_week = $11,
|
||||||
time_til_dormant = $12,
|
failure_ttl = $12,
|
||||||
time_til_dormant_autodelete = $13
|
time_til_dormant = $13,
|
||||||
|
time_til_dormant_autodelete = $14
|
||||||
WHERE
|
WHERE
|
||||||
id = $1
|
id = $1
|
||||||
;
|
;
|
||||||
|
|
|
@ -117,7 +117,10 @@ type TemplateScheduleOptions struct {
|
||||||
UserAutostartEnabled bool `json:"user_autostart_enabled"`
|
UserAutostartEnabled bool `json:"user_autostart_enabled"`
|
||||||
UserAutostopEnabled bool `json:"user_autostop_enabled"`
|
UserAutostopEnabled bool `json:"user_autostop_enabled"`
|
||||||
DefaultTTL time.Duration `json:"default_ttl"`
|
DefaultTTL time.Duration `json:"default_ttl"`
|
||||||
MaxTTL time.Duration `json:"max_ttl"`
|
// ActivityBump dictates the duration to bump the workspace's deadline by if
|
||||||
|
// Coder detects activity from the user. A value of 0 means no bumping.
|
||||||
|
ActivityBump time.Duration `json:"activity_bump"`
|
||||||
|
MaxTTL time.Duration `json:"max_ttl"`
|
||||||
// UseMaxTTL dictates whether the max_ttl should be used instead of
|
// UseMaxTTL dictates whether the max_ttl should be used instead of
|
||||||
// autostop_requirement for this template. This is governed by the template
|
// autostop_requirement for this template. This is governed by the template
|
||||||
// and licensing.
|
// and licensing.
|
||||||
|
@ -181,6 +184,7 @@ func (*agplTemplateScheduleStore) Get(ctx context.Context, db database.Store, te
|
||||||
UserAutostartEnabled: true,
|
UserAutostartEnabled: true,
|
||||||
UserAutostopEnabled: true,
|
UserAutostopEnabled: true,
|
||||||
DefaultTTL: time.Duration(tpl.DefaultTTL),
|
DefaultTTL: time.Duration(tpl.DefaultTTL),
|
||||||
|
ActivityBump: time.Duration(tpl.ActivityBump),
|
||||||
// Disregard the values in the database, since AutostopRequirement,
|
// Disregard the values in the database, since AutostopRequirement,
|
||||||
// FailureTTL, TimeTilDormant, and TimeTilDormantAutoDelete are enterprise features.
|
// FailureTTL, TimeTilDormant, and TimeTilDormantAutoDelete are enterprise features.
|
||||||
UseMaxTTL: false,
|
UseMaxTTL: false,
|
||||||
|
@ -205,7 +209,7 @@ func (*agplTemplateScheduleStore) Set(ctx context.Context, db database.Store, tp
|
||||||
ctx, span := tracing.StartSpan(ctx)
|
ctx, span := tracing.StartSpan(ctx)
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
if int64(opts.DefaultTTL) == tpl.DefaultTTL {
|
if int64(opts.DefaultTTL) == tpl.DefaultTTL && int64(opts.ActivityBump) == tpl.ActivityBump {
|
||||||
// Avoid updating the UpdatedAt timestamp if nothing will be changed.
|
// Avoid updating the UpdatedAt timestamp if nothing will be changed.
|
||||||
return tpl, nil
|
return tpl, nil
|
||||||
}
|
}
|
||||||
|
@ -213,9 +217,10 @@ func (*agplTemplateScheduleStore) Set(ctx context.Context, db database.Store, tp
|
||||||
var template database.Template
|
var template database.Template
|
||||||
err := db.InTx(func(db database.Store) error {
|
err := db.InTx(func(db database.Store) error {
|
||||||
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
||||||
ID: tpl.ID,
|
ID: tpl.ID,
|
||||||
UpdatedAt: dbtime.Now(),
|
UpdatedAt: dbtime.Now(),
|
||||||
DefaultTTL: int64(opts.DefaultTTL),
|
DefaultTTL: int64(opts.DefaultTTL),
|
||||||
|
ActivityBump: int64(opts.ActivityBump),
|
||||||
// Don't allow changing these settings, but keep the value in the DB (to
|
// Don't allow changing these settings, but keep the value in the DB (to
|
||||||
// avoid clearing settings if the license has an issue).
|
// avoid clearing settings if the license has an issue).
|
||||||
UseMaxTtl: tpl.UseMaxTtl,
|
UseMaxTtl: tpl.UseMaxTtl,
|
||||||
|
|
|
@ -224,6 +224,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||||
|
|
||||||
var (
|
var (
|
||||||
defaultTTL time.Duration
|
defaultTTL time.Duration
|
||||||
|
activityBump = time.Hour // default
|
||||||
maxTTL time.Duration
|
maxTTL time.Duration
|
||||||
autostopRequirementDaysOfWeek []string
|
autostopRequirementDaysOfWeek []string
|
||||||
autostartRequirementDaysOfWeek []string
|
autostartRequirementDaysOfWeek []string
|
||||||
|
@ -235,6 +236,9 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||||
if createTemplate.DefaultTTLMillis != nil {
|
if createTemplate.DefaultTTLMillis != nil {
|
||||||
defaultTTL = time.Duration(*createTemplate.DefaultTTLMillis) * time.Millisecond
|
defaultTTL = time.Duration(*createTemplate.DefaultTTLMillis) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
if createTemplate.ActivityBumpMillis != nil {
|
||||||
|
activityBump = time.Duration(*createTemplate.ActivityBumpMillis) * time.Millisecond
|
||||||
|
}
|
||||||
if createTemplate.AutostopRequirement != nil {
|
if createTemplate.AutostopRequirement != nil {
|
||||||
autostopRequirementDaysOfWeek = createTemplate.AutostopRequirement.DaysOfWeek
|
autostopRequirementDaysOfWeek = createTemplate.AutostopRequirement.DaysOfWeek
|
||||||
autostopRequirementWeeks = createTemplate.AutostopRequirement.Weeks
|
autostopRequirementWeeks = createTemplate.AutostopRequirement.Weeks
|
||||||
|
@ -263,6 +267,9 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||||
if defaultTTL < 0 {
|
if defaultTTL < 0 {
|
||||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
|
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
|
||||||
}
|
}
|
||||||
|
if activityBump < 0 {
|
||||||
|
validErrs = append(validErrs, codersdk.ValidationError{Field: "activity_bump_ms", Detail: "Must be a positive integer."})
|
||||||
|
}
|
||||||
if maxTTL < 0 {
|
if maxTTL < 0 {
|
||||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."})
|
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."})
|
||||||
}
|
}
|
||||||
|
@ -313,7 +320,6 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||||
|
|
||||||
var (
|
var (
|
||||||
dbTemplate database.Template
|
dbTemplate database.Template
|
||||||
template codersdk.Template
|
|
||||||
|
|
||||||
allowUserCancelWorkspaceJobs = ptr.NilToDefault(createTemplate.AllowUserCancelWorkspaceJobs, false)
|
allowUserCancelWorkspaceJobs = ptr.NilToDefault(createTemplate.AllowUserCancelWorkspaceJobs, false)
|
||||||
allowUserAutostart = ptr.NilToDefault(createTemplate.AllowUserAutostart, true)
|
allowUserAutostart = ptr.NilToDefault(createTemplate.AllowUserAutostart, true)
|
||||||
|
@ -368,6 +374,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||||
UserAutostopEnabled: allowUserAutostop,
|
UserAutostopEnabled: allowUserAutostop,
|
||||||
UseMaxTTL: maxTTL > 0,
|
UseMaxTTL: maxTTL > 0,
|
||||||
DefaultTTL: defaultTTL,
|
DefaultTTL: defaultTTL,
|
||||||
|
ActivityBump: activityBump,
|
||||||
MaxTTL: maxTTL,
|
MaxTTL: maxTTL,
|
||||||
// Some of these values are enterprise-only, but the
|
// Some of these values are enterprise-only, but the
|
||||||
// TemplateScheduleStore will handle avoiding setting them if
|
// TemplateScheduleStore will handle avoiding setting them if
|
||||||
|
@ -409,7 +416,6 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||||
}
|
}
|
||||||
templateVersionAudit.New = newTemplateVersion
|
templateVersionAudit.New = newTemplateVersion
|
||||||
|
|
||||||
template = api.convertTemplate(dbTemplate)
|
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -425,7 +431,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||||
TemplateVersions: []telemetry.TemplateVersion{telemetry.ConvertTemplateVersion(templateVersion)},
|
TemplateVersions: []telemetry.TemplateVersion{telemetry.ConvertTemplateVersion(templateVersion)},
|
||||||
})
|
})
|
||||||
|
|
||||||
httpapi.Write(ctx, rw, http.StatusCreated, template)
|
httpapi.Write(ctx, rw, http.StatusCreated, api.convertTemplate(dbTemplate))
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Get templates by organization
|
// @Summary Get templates by organization
|
||||||
|
@ -565,6 +571,9 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||||
if req.DefaultTTLMillis < 0 {
|
if req.DefaultTTLMillis < 0 {
|
||||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
|
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
|
||||||
}
|
}
|
||||||
|
if req.ActivityBumpMillis < 0 {
|
||||||
|
validErrs = append(validErrs, codersdk.ValidationError{Field: "activity_bump_ms", Detail: "Must be a positive integer."})
|
||||||
|
}
|
||||||
if req.MaxTTLMillis < 0 {
|
if req.MaxTTLMillis < 0 {
|
||||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."})
|
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."})
|
||||||
}
|
}
|
||||||
|
@ -648,6 +657,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||||
req.AllowUserAutostop == template.AllowUserAutostop &&
|
req.AllowUserAutostop == template.AllowUserAutostop &&
|
||||||
req.AllowUserCancelWorkspaceJobs == template.AllowUserCancelWorkspaceJobs &&
|
req.AllowUserCancelWorkspaceJobs == template.AllowUserCancelWorkspaceJobs &&
|
||||||
req.DefaultTTLMillis == time.Duration(template.DefaultTTL).Milliseconds() &&
|
req.DefaultTTLMillis == time.Duration(template.DefaultTTL).Milliseconds() &&
|
||||||
|
req.ActivityBumpMillis == time.Duration(template.ActivityBump).Milliseconds() &&
|
||||||
useMaxTTL == scheduleOpts.UseMaxTTL &&
|
useMaxTTL == scheduleOpts.UseMaxTTL &&
|
||||||
req.MaxTTLMillis == time.Duration(template.MaxTTL).Milliseconds() &&
|
req.MaxTTLMillis == time.Duration(template.MaxTTL).Milliseconds() &&
|
||||||
autostopRequirementDaysOfWeekParsed == scheduleOpts.AutostopRequirement.DaysOfWeek &&
|
autostopRequirementDaysOfWeekParsed == scheduleOpts.AutostopRequirement.DaysOfWeek &&
|
||||||
|
@ -703,12 +713,14 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultTTL := time.Duration(req.DefaultTTLMillis) * time.Millisecond
|
defaultTTL := time.Duration(req.DefaultTTLMillis) * time.Millisecond
|
||||||
|
activityBump := time.Duration(req.ActivityBumpMillis) * time.Millisecond
|
||||||
maxTTL := time.Duration(req.MaxTTLMillis) * time.Millisecond
|
maxTTL := time.Duration(req.MaxTTLMillis) * time.Millisecond
|
||||||
failureTTL := time.Duration(req.FailureTTLMillis) * time.Millisecond
|
failureTTL := time.Duration(req.FailureTTLMillis) * time.Millisecond
|
||||||
inactivityTTL := time.Duration(req.TimeTilDormantMillis) * time.Millisecond
|
inactivityTTL := time.Duration(req.TimeTilDormantMillis) * time.Millisecond
|
||||||
timeTilDormantAutoDelete := time.Duration(req.TimeTilDormantAutoDeleteMillis) * time.Millisecond
|
timeTilDormantAutoDelete := time.Duration(req.TimeTilDormantAutoDeleteMillis) * time.Millisecond
|
||||||
|
|
||||||
if defaultTTL != time.Duration(template.DefaultTTL) ||
|
if defaultTTL != time.Duration(template.DefaultTTL) ||
|
||||||
|
activityBump != time.Duration(template.ActivityBump) ||
|
||||||
useMaxTTL != scheduleOpts.UseMaxTTL ||
|
useMaxTTL != scheduleOpts.UseMaxTTL ||
|
||||||
maxTTL != time.Duration(template.MaxTTL) ||
|
maxTTL != time.Duration(template.MaxTTL) ||
|
||||||
autostopRequirementDaysOfWeekParsed != scheduleOpts.AutostopRequirement.DaysOfWeek ||
|
autostopRequirementDaysOfWeekParsed != scheduleOpts.AutostopRequirement.DaysOfWeek ||
|
||||||
|
@ -726,6 +738,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||||
UserAutostartEnabled: req.AllowUserAutostart,
|
UserAutostartEnabled: req.AllowUserAutostart,
|
||||||
UserAutostopEnabled: req.AllowUserAutostop,
|
UserAutostopEnabled: req.AllowUserAutostop,
|
||||||
DefaultTTL: defaultTTL,
|
DefaultTTL: defaultTTL,
|
||||||
|
ActivityBump: activityBump,
|
||||||
UseMaxTTL: useMaxTTL,
|
UseMaxTTL: useMaxTTL,
|
||||||
MaxTTL: maxTTL,
|
MaxTTL: maxTTL,
|
||||||
AutostopRequirement: schedule.TemplateAutostopRequirement{
|
AutostopRequirement: schedule.TemplateAutostopRequirement{
|
||||||
|
@ -875,6 +888,7 @@ func (api *API) convertTemplate(
|
||||||
Description: template.Description,
|
Description: template.Description,
|
||||||
Icon: template.Icon,
|
Icon: template.Icon,
|
||||||
DefaultTTLMillis: time.Duration(template.DefaultTTL).Milliseconds(),
|
DefaultTTLMillis: time.Duration(template.DefaultTTL).Milliseconds(),
|
||||||
|
ActivityBumpMillis: time.Duration(template.ActivityBump).Milliseconds(),
|
||||||
UseMaxTTL: template.UseMaxTtl,
|
UseMaxTTL: template.UseMaxTtl,
|
||||||
MaxTTLMillis: time.Duration(template.MaxTTL).Milliseconds(),
|
MaxTTLMillis: time.Duration(template.MaxTTL).Milliseconds(),
|
||||||
CreatedByID: template.CreatedBy,
|
CreatedByID: template.CreatedBy,
|
||||||
|
|
|
@ -57,7 +57,10 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||||
|
|
||||||
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
|
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
|
||||||
|
|
||||||
expected := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
|
expected := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
|
||||||
|
ctr.ActivityBumpMillis = ptr.Ref((3 * time.Hour).Milliseconds())
|
||||||
|
})
|
||||||
|
assert.Equal(t, (3 * time.Hour).Milliseconds(), expected.ActivityBumpMillis)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -67,6 +70,7 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, expected.Name, got.Name)
|
assert.Equal(t, expected.Name, got.Name)
|
||||||
assert.Equal(t, expected.Description, got.Description)
|
assert.Equal(t, expected.Description, got.Description)
|
||||||
|
assert.Equal(t, expected.ActivityBumpMillis, got.ActivityBumpMillis)
|
||||||
|
|
||||||
require.Len(t, auditor.AuditLogs(), 3)
|
require.Len(t, auditor.AuditLogs(), 3)
|
||||||
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[0].Action)
|
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[0].Action)
|
||||||
|
@ -268,6 +272,7 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||||
AllowUserAutostart: options.UserAutostartEnabled,
|
AllowUserAutostart: options.UserAutostartEnabled,
|
||||||
AllowUserAutostop: options.UserAutostopEnabled,
|
AllowUserAutostop: options.UserAutostopEnabled,
|
||||||
DefaultTTL: int64(options.DefaultTTL),
|
DefaultTTL: int64(options.DefaultTTL),
|
||||||
|
ActivityBump: int64(options.ActivityBump),
|
||||||
UseMaxTtl: options.UseMaxTTL,
|
UseMaxTtl: options.UseMaxTTL,
|
||||||
MaxTTL: int64(options.MaxTTL),
|
MaxTTL: int64(options.MaxTTL),
|
||||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||||
|
@ -320,6 +325,7 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||||
AllowUserAutostart: options.UserAutostartEnabled,
|
AllowUserAutostart: options.UserAutostartEnabled,
|
||||||
AllowUserAutostop: options.UserAutostopEnabled,
|
AllowUserAutostop: options.UserAutostopEnabled,
|
||||||
DefaultTTL: int64(options.DefaultTTL),
|
DefaultTTL: int64(options.DefaultTTL),
|
||||||
|
ActivityBump: int64(options.ActivityBump),
|
||||||
UseMaxTtl: options.UseMaxTTL,
|
UseMaxTtl: options.UseMaxTTL,
|
||||||
MaxTTL: int64(options.MaxTTL),
|
MaxTTL: int64(options.MaxTTL),
|
||||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||||
|
@ -508,6 +514,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||||
|
assert.Equal(t, (1 * time.Hour).Milliseconds(), template.ActivityBumpMillis)
|
||||||
|
|
||||||
req := codersdk.UpdateTemplateMeta{
|
req := codersdk.UpdateTemplateMeta{
|
||||||
Name: "new-template-name",
|
Name: "new-template-name",
|
||||||
|
@ -515,6 +522,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||||
Description: "lorem ipsum dolor sit amet et cetera",
|
Description: "lorem ipsum dolor sit amet et cetera",
|
||||||
Icon: "/icon/new-icon.png",
|
Icon: "/icon/new-icon.png",
|
||||||
DefaultTTLMillis: 12 * time.Hour.Milliseconds(),
|
DefaultTTLMillis: 12 * time.Hour.Milliseconds(),
|
||||||
|
ActivityBumpMillis: 3 * time.Hour.Milliseconds(),
|
||||||
AllowUserCancelWorkspaceJobs: false,
|
AllowUserCancelWorkspaceJobs: false,
|
||||||
}
|
}
|
||||||
// It is unfortunate we need to sleep, but the test can fail if the
|
// It is unfortunate we need to sleep, but the test can fail if the
|
||||||
|
@ -532,6 +540,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||||
assert.Equal(t, req.Description, updated.Description)
|
assert.Equal(t, req.Description, updated.Description)
|
||||||
assert.Equal(t, req.Icon, updated.Icon)
|
assert.Equal(t, req.Icon, updated.Icon)
|
||||||
assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis)
|
assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis)
|
||||||
|
assert.Equal(t, req.ActivityBumpMillis, updated.ActivityBumpMillis)
|
||||||
assert.False(t, req.AllowUserCancelWorkspaceJobs)
|
assert.False(t, req.AllowUserCancelWorkspaceJobs)
|
||||||
|
|
||||||
// Extra paranoid: did it _really_ happen?
|
// Extra paranoid: did it _really_ happen?
|
||||||
|
@ -543,6 +552,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||||
assert.Equal(t, req.Description, updated.Description)
|
assert.Equal(t, req.Description, updated.Description)
|
||||||
assert.Equal(t, req.Icon, updated.Icon)
|
assert.Equal(t, req.Icon, updated.Icon)
|
||||||
assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis)
|
assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis)
|
||||||
|
assert.Equal(t, req.ActivityBumpMillis, updated.ActivityBumpMillis)
|
||||||
assert.False(t, req.AllowUserCancelWorkspaceJobs)
|
assert.False(t, req.AllowUserCancelWorkspaceJobs)
|
||||||
|
|
||||||
require.Len(t, auditor.AuditLogs(), 5)
|
require.Len(t, auditor.AuditLogs(), 5)
|
||||||
|
@ -707,6 +717,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||||
AllowUserAutostart: options.UserAutostartEnabled,
|
AllowUserAutostart: options.UserAutostartEnabled,
|
||||||
AllowUserAutostop: options.UserAutostopEnabled,
|
AllowUserAutostop: options.UserAutostopEnabled,
|
||||||
DefaultTTL: int64(options.DefaultTTL),
|
DefaultTTL: int64(options.DefaultTTL),
|
||||||
|
ActivityBump: int64(options.ActivityBump),
|
||||||
MaxTTL: int64(options.MaxTTL),
|
MaxTTL: int64(options.MaxTTL),
|
||||||
UseMaxTtl: options.UseMaxTTL,
|
UseMaxTtl: options.UseMaxTTL,
|
||||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||||
|
@ -1015,6 +1026,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||||
Description: template.Description,
|
Description: template.Description,
|
||||||
Icon: template.Icon,
|
Icon: template.Icon,
|
||||||
DefaultTTLMillis: template.DefaultTTLMillis,
|
DefaultTTLMillis: template.DefaultTTLMillis,
|
||||||
|
ActivityBumpMillis: template.ActivityBumpMillis,
|
||||||
AutostopRequirement: nil,
|
AutostopRequirement: nil,
|
||||||
AllowUserAutostart: template.AllowUserAutostart,
|
AllowUserAutostart: template.AllowUserAutostart,
|
||||||
AllowUserAutostop: template.AllowUserAutostop,
|
AllowUserAutostop: template.AllowUserAutostop,
|
||||||
|
@ -1105,6 +1117,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||||
AllowUserAutostart: options.UserAutostartEnabled,
|
AllowUserAutostart: options.UserAutostartEnabled,
|
||||||
AllowUserAutostop: options.UserAutostopEnabled,
|
AllowUserAutostop: options.UserAutostopEnabled,
|
||||||
DefaultTTL: int64(options.DefaultTTL),
|
DefaultTTL: int64(options.DefaultTTL),
|
||||||
|
ActivityBump: int64(options.ActivityBump),
|
||||||
UseMaxTtl: options.UseMaxTTL,
|
UseMaxTtl: options.UseMaxTTL,
|
||||||
MaxTTL: int64(options.MaxTTL),
|
MaxTTL: int64(options.MaxTTL),
|
||||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||||
|
@ -1177,6 +1190,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||||
AllowUserAutostart: options.UserAutostartEnabled,
|
AllowUserAutostart: options.UserAutostartEnabled,
|
||||||
AllowUserAutostop: options.UserAutostopEnabled,
|
AllowUserAutostop: options.UserAutostopEnabled,
|
||||||
DefaultTTL: int64(options.DefaultTTL),
|
DefaultTTL: int64(options.DefaultTTL),
|
||||||
|
ActivityBump: int64(options.ActivityBump),
|
||||||
UseMaxTtl: options.UseMaxTTL,
|
UseMaxTtl: options.UseMaxTTL,
|
||||||
MaxTTL: int64(options.MaxTTL),
|
MaxTTL: int64(options.MaxTTL),
|
||||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||||
|
|
|
@ -84,6 +84,10 @@ type CreateTemplateRequest struct {
|
||||||
// DefaultTTLMillis allows optionally specifying the default TTL
|
// DefaultTTLMillis allows optionally specifying the default TTL
|
||||||
// for all workspaces created from this template.
|
// for all workspaces created from this template.
|
||||||
DefaultTTLMillis *int64 `json:"default_ttl_ms,omitempty"`
|
DefaultTTLMillis *int64 `json:"default_ttl_ms,omitempty"`
|
||||||
|
// ActivityBumpMillis allows optionally specifying the activity bump
|
||||||
|
// duration for all workspaces created from this template. Defaults to 1h
|
||||||
|
// but can be set to 0 to disable activity bumping.
|
||||||
|
ActivityBumpMillis *int64 `json:"activity_bump_ms,omitempty"`
|
||||||
// TODO(@dean): remove max_ttl once autostop_requirement is matured
|
// TODO(@dean): remove max_ttl once autostop_requirement is matured
|
||||||
// Only one of MaxTTLMillis or AutostopRequirement can be specified.
|
// Only one of MaxTTLMillis or AutostopRequirement can be specified.
|
||||||
MaxTTLMillis *int64 `json:"max_ttl_ms,omitempty"`
|
MaxTTLMillis *int64 `json:"max_ttl_ms,omitempty"`
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Template struct {
|
||||||
DeprecationMessage string `json:"deprecation_message"`
|
DeprecationMessage string `json:"deprecation_message"`
|
||||||
Icon string `json:"icon"`
|
Icon string `json:"icon"`
|
||||||
DefaultTTLMillis int64 `json:"default_ttl_ms"`
|
DefaultTTLMillis int64 `json:"default_ttl_ms"`
|
||||||
|
ActivityBumpMillis int64 `json:"activity_bump_ms"`
|
||||||
// UseMaxTTL picks whether to use the deprecated max TTL for the template or
|
// UseMaxTTL picks whether to use the deprecated max TTL for the template or
|
||||||
// the new autostop requirement.
|
// the new autostop requirement.
|
||||||
UseMaxTTL bool `json:"use_max_ttl"`
|
UseMaxTTL bool `json:"use_max_ttl"`
|
||||||
|
@ -208,6 +209,10 @@ type UpdateTemplateMeta struct {
|
||||||
Description string `json:"description,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
Icon string `json:"icon,omitempty"`
|
Icon string `json:"icon,omitempty"`
|
||||||
DefaultTTLMillis int64 `json:"default_ttl_ms,omitempty"`
|
DefaultTTLMillis int64 `json:"default_ttl_ms,omitempty"`
|
||||||
|
// ActivityBumpMillis allows optionally specifying the activity bump
|
||||||
|
// duration for all workspaces created from this template. Defaults to 1h
|
||||||
|
// but can be set to 0 to disable activity bumping.
|
||||||
|
ActivityBumpMillis int64 `json:"activity_bump_ms,omitempty"`
|
||||||
// TODO(@dean): remove max_ttl once autostop_requirement is matured
|
// TODO(@dean): remove max_ttl once autostop_requirement is matured
|
||||||
// Only one of MaxTTLMillis or AutostopRequirement can be specified.
|
// Only one of MaxTTLMillis or AutostopRequirement can be specified.
|
||||||
MaxTTLMillis int64 `json:"max_ttl_ms,omitempty"`
|
MaxTTLMillis int64 `json:"max_ttl_ms,omitempty"`
|
||||||
|
|
|
@ -8,20 +8,20 @@ We track the following resources:
|
||||||
|
|
||||||
<!-- Code generated by 'make docs/admin/audit-logs.md'. DO NOT EDIT -->
|
<!-- Code generated by 'make docs/admin/audit-logs.md'. DO NOT EDIT -->
|
||||||
|
|
||||||
| <b>Resource<b> | |
|
| <b>Resource<b> | |
|
||||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| APIKey<br><i>login, logout, register, create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>ip_address</td><td>false</td></tr><tr><td>last_used</td><td>true</td></tr><tr><td>lifetime_seconds</td><td>false</td></tr><tr><td>login_type</td><td>false</td></tr><tr><td>scope</td><td>false</td></tr><tr><td>token_name</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
| APIKey<br><i>login, logout, register, create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>ip_address</td><td>false</td></tr><tr><td>last_used</td><td>true</td></tr><tr><td>lifetime_seconds</td><td>false</td></tr><tr><td>login_type</td><td>false</td></tr><tr><td>scope</td><td>false</td></tr><tr><td>token_name</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||||
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||||
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
|
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
|
||||||
| GitSSHKey<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>false</td></tr><tr><td>private_key</td><td>true</td></tr><tr><td>public_key</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
| GitSSHKey<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>false</td></tr><tr><td>private_key</td><td>true</td></tr><tr><td>public_key</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||||
| HealthSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>dismissed_healthchecks</td><td>true</td></tr><tr><td>id</td><td>false</td></tr></tbody></table> |
|
| HealthSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>dismissed_healthchecks</td><td>true</td></tr><tr><td>id</td><td>false</td></tr></tbody></table> |
|
||||||
| License<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>exp</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwt</td><td>false</td></tr><tr><td>uploaded_at</td><td>true</td></tr><tr><td>uuid</td><td>true</td></tr></tbody></table> |
|
| License<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>exp</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwt</td><td>false</td></tr><tr><td>uploaded_at</td><td>true</td></tr><tr><td>uuid</td><td>true</td></tr></tbody></table> |
|
||||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>active_version_id</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_ttl</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_max_ttl</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_ttl</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_max_ttl</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>theme_preference</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>theme_preference</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||||
| Workspace<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
| Workspace<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||||
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
||||||
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||||
|
|
||||||
<!-- End generated by 'make docs/admin/audit-logs.md'. -->
|
<!-- End generated by 'make docs/admin/audit-logs.md'. -->
|
||||||
|
|
||||||
|
|
|
@ -1620,6 +1620,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"activity_bump_ms": 0,
|
||||||
"allow_user_autostart": true,
|
"allow_user_autostart": true,
|
||||||
"allow_user_autostop": true,
|
"allow_user_autostop": true,
|
||||||
"allow_user_cancel_workspace_jobs": true,
|
"allow_user_cancel_workspace_jobs": true,
|
||||||
|
@ -1649,6 +1650,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||||
|
|
||||||
| Name | Type | Required | Restrictions | Description |
|
| Name | Type | Required | Restrictions | Description |
|
||||||
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `activity_bump_ms` | integer | false | | Activity bump ms allows optionally specifying the activity bump duration for all workspaces created from this template. Defaults to 1h but can be set to 0 to disable activity bumping. |
|
||||||
| `allow_user_autostart` | boolean | false | | Allow user autostart allows users to set a schedule for autostarting their workspace. By default this is true. This can only be disabled when using an enterprise license. |
|
| `allow_user_autostart` | boolean | false | | Allow user autostart allows users to set a schedule for autostarting their workspace. By default this is true. This can only be disabled when using an enterprise license. |
|
||||||
| `allow_user_autostop` | boolean | false | | Allow user autostop allows users to set a custom workspace TTL to use in place of the template's DefaultTTL field. By default this is true. If false, the DefaultTTL will always be used. This can only be disabled when using an enterprise license. |
|
| `allow_user_autostop` | boolean | false | | Allow user autostop allows users to set a custom workspace TTL to use in place of the template's DefaultTTL field. By default this is true. If false, the DefaultTTL will always be used. This can only be disabled when using an enterprise license. |
|
||||||
| `allow_user_cancel_workspace_jobs` | boolean | false | | Allow users to cancel in-progress workspace jobs. \*bool as the default value is "true". |
|
| `allow_user_cancel_workspace_jobs` | boolean | false | | Allow users to cancel in-progress workspace jobs. \*bool as the default value is "true". |
|
||||||
|
@ -4643,6 +4645,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||||
{
|
{
|
||||||
"active_user_count": 0,
|
"active_user_count": 0,
|
||||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||||
|
"activity_bump_ms": 0,
|
||||||
"allow_user_autostart": true,
|
"allow_user_autostart": true,
|
||||||
"allow_user_autostop": true,
|
"allow_user_autostop": true,
|
||||||
"allow_user_cancel_workspace_jobs": true,
|
"allow_user_cancel_workspace_jobs": true,
|
||||||
|
@ -4692,6 +4695,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||||
| ---------------------------------- | ------------------------------------------------------------------------------ | -------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------------------------- | ------------------------------------------------------------------------------ | -------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
| `active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||||
| `active_version_id` | string | false | | |
|
| `active_version_id` | string | false | | |
|
||||||
|
| `activity_bump_ms` | integer | false | | |
|
||||||
| `allow_user_autostart` | boolean | false | | Allow user autostart and AllowUserAutostop are enterprise-only. Their values are only used if your license is entitled to use the advanced template scheduling feature. |
|
| `allow_user_autostart` | boolean | false | | Allow user autostart and AllowUserAutostop are enterprise-only. Their values are only used if your license is entitled to use the advanced template scheduling feature. |
|
||||||
| `allow_user_autostop` | boolean | false | | |
|
| `allow_user_autostop` | boolean | false | | |
|
||||||
| `allow_user_cancel_workspace_jobs` | boolean | false | | |
|
| `allow_user_cancel_workspace_jobs` | boolean | false | | |
|
||||||
|
|
|
@ -28,6 +28,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||||
{
|
{
|
||||||
"active_user_count": 0,
|
"active_user_count": 0,
|
||||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||||
|
"activity_bump_ms": 0,
|
||||||
"allow_user_autostart": true,
|
"allow_user_autostart": true,
|
||||||
"allow_user_autostop": true,
|
"allow_user_autostop": true,
|
||||||
"allow_user_cancel_workspace_jobs": true,
|
"allow_user_cancel_workspace_jobs": true,
|
||||||
|
@ -87,6 +88,7 @@ Status Code **200**
|
||||||
| `[array item]` | array | false | | |
|
| `[array item]` | array | false | | |
|
||||||
| `» active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
| `» active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||||
| `» active_version_id` | string(uuid) | false | | |
|
| `» active_version_id` | string(uuid) | false | | |
|
||||||
|
| `» activity_bump_ms` | integer | false | | |
|
||||||
| `» allow_user_autostart` | boolean | false | | Allow user autostart and AllowUserAutostop are enterprise-only. Their values are only used if your license is entitled to use the advanced template scheduling feature. |
|
| `» allow_user_autostart` | boolean | false | | Allow user autostart and AllowUserAutostop are enterprise-only. Their values are only used if your license is entitled to use the advanced template scheduling feature. |
|
||||||
| `» allow_user_autostop` | boolean | false | | |
|
| `» allow_user_autostop` | boolean | false | | |
|
||||||
| `» allow_user_cancel_workspace_jobs` | boolean | false | | |
|
| `» allow_user_cancel_workspace_jobs` | boolean | false | | |
|
||||||
|
@ -147,6 +149,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"activity_bump_ms": 0,
|
||||||
"allow_user_autostart": true,
|
"allow_user_autostart": true,
|
||||||
"allow_user_autostop": true,
|
"allow_user_autostop": true,
|
||||||
"allow_user_cancel_workspace_jobs": true,
|
"allow_user_cancel_workspace_jobs": true,
|
||||||
|
@ -187,6 +190,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
||||||
{
|
{
|
||||||
"active_user_count": 0,
|
"active_user_count": 0,
|
||||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||||
|
"activity_bump_ms": 0,
|
||||||
"allow_user_autostart": true,
|
"allow_user_autostart": true,
|
||||||
"allow_user_autostop": true,
|
"allow_user_autostop": true,
|
||||||
"allow_user_cancel_workspace_jobs": true,
|
"allow_user_cancel_workspace_jobs": true,
|
||||||
|
@ -326,6 +330,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||||
{
|
{
|
||||||
"active_user_count": 0,
|
"active_user_count": 0,
|
||||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||||
|
"activity_bump_ms": 0,
|
||||||
"allow_user_autostart": true,
|
"allow_user_autostart": true,
|
||||||
"allow_user_autostop": true,
|
"allow_user_autostop": true,
|
||||||
"allow_user_cancel_workspace_jobs": true,
|
"allow_user_cancel_workspace_jobs": true,
|
||||||
|
@ -641,6 +646,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template} \
|
||||||
{
|
{
|
||||||
"active_user_count": 0,
|
"active_user_count": 0,
|
||||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||||
|
"activity_bump_ms": 0,
|
||||||
"allow_user_autostart": true,
|
"allow_user_autostart": true,
|
||||||
"allow_user_autostop": true,
|
"allow_user_autostop": true,
|
||||||
"allow_user_cancel_workspace_jobs": true,
|
"allow_user_cancel_workspace_jobs": true,
|
||||||
|
@ -763,6 +769,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \
|
||||||
{
|
{
|
||||||
"active_user_count": 0,
|
"active_user_count": 0,
|
||||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||||
|
"activity_bump_ms": 0,
|
||||||
"allow_user_autostart": true,
|
"allow_user_autostart": true,
|
||||||
"allow_user_autostop": true,
|
"allow_user_autostop": true,
|
||||||
"allow_user_cancel_workspace_jobs": true,
|
"allow_user_cancel_workspace_jobs": true,
|
||||||
|
|
|
@ -12,6 +12,14 @@ coder templates edit [flags] <template>
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
|
### --activity-bump
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| ---- | --------------------- |
|
||||||
|
| Type | <code>duration</code> |
|
||||||
|
|
||||||
|
Edit the template activity bump - workspaces created from this template will have their shutdown time bumped by this value when activity is detected. Maps to "Activity bump" in the UI.
|
||||||
|
|
||||||
### --allow-user-autostart
|
### --allow-user-autostart
|
||||||
|
|
||||||
| | |
|
| | |
|
||||||
|
|
|
@ -88,6 +88,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
||||||
"time_til_dormant_autodelete": ActionTrack,
|
"time_til_dormant_autodelete": ActionTrack,
|
||||||
"require_active_version": ActionTrack,
|
"require_active_version": ActionTrack,
|
||||||
"deprecated": ActionTrack,
|
"deprecated": ActionTrack,
|
||||||
|
"activity_bump": ActionTrack,
|
||||||
},
|
},
|
||||||
&database.TemplateVersion{}: {
|
&database.TemplateVersion{}: {
|
||||||
"id": ActionTrack,
|
"id": ActionTrack,
|
||||||
|
|
|
@ -75,6 +75,7 @@ func (*EnterpriseTemplateScheduleStore) Get(ctx context.Context, db database.Sto
|
||||||
UserAutostartEnabled: tpl.AllowUserAutostart,
|
UserAutostartEnabled: tpl.AllowUserAutostart,
|
||||||
UserAutostopEnabled: tpl.AllowUserAutostop,
|
UserAutostopEnabled: tpl.AllowUserAutostop,
|
||||||
DefaultTTL: time.Duration(tpl.DefaultTTL),
|
DefaultTTL: time.Duration(tpl.DefaultTTL),
|
||||||
|
ActivityBump: time.Duration(tpl.ActivityBump),
|
||||||
MaxTTL: time.Duration(tpl.MaxTTL),
|
MaxTTL: time.Duration(tpl.MaxTTL),
|
||||||
UseMaxTTL: tpl.UseMaxTtl,
|
UseMaxTTL: tpl.UseMaxTtl,
|
||||||
AutostopRequirement: agpl.TemplateAutostopRequirement{
|
AutostopRequirement: agpl.TemplateAutostopRequirement{
|
||||||
|
@ -103,6 +104,7 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
|
||||||
}
|
}
|
||||||
|
|
||||||
if int64(opts.DefaultTTL) == tpl.DefaultTTL &&
|
if int64(opts.DefaultTTL) == tpl.DefaultTTL &&
|
||||||
|
int64(opts.ActivityBump) == tpl.ActivityBump &&
|
||||||
opts.UseMaxTTL != tpl.UseMaxTtl &&
|
opts.UseMaxTTL != tpl.UseMaxTtl &&
|
||||||
int64(opts.MaxTTL) == tpl.MaxTTL &&
|
int64(opts.MaxTTL) == tpl.MaxTTL &&
|
||||||
int16(opts.AutostopRequirement.DaysOfWeek) == tpl.AutostopRequirementDaysOfWeek &&
|
int16(opts.AutostopRequirement.DaysOfWeek) == tpl.AutostopRequirementDaysOfWeek &&
|
||||||
|
@ -138,6 +140,7 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
|
||||||
AllowUserAutostart: opts.UserAutostartEnabled,
|
AllowUserAutostart: opts.UserAutostartEnabled,
|
||||||
AllowUserAutostop: opts.UserAutostopEnabled,
|
AllowUserAutostop: opts.UserAutostopEnabled,
|
||||||
DefaultTTL: int64(opts.DefaultTTL),
|
DefaultTTL: int64(opts.DefaultTTL),
|
||||||
|
ActivityBump: int64(opts.ActivityBump),
|
||||||
UseMaxTtl: opts.UseMaxTTL,
|
UseMaxTtl: opts.UseMaxTTL,
|
||||||
MaxTTL: int64(opts.MaxTTL),
|
MaxTTL: int64(opts.MaxTTL),
|
||||||
AutostopRequirementDaysOfWeek: int16(opts.AutostopRequirement.DaysOfWeek),
|
AutostopRequirementDaysOfWeek: int16(opts.AutostopRequirement.DaysOfWeek),
|
||||||
|
|
|
@ -225,6 +225,7 @@ export interface CreateTemplateRequest {
|
||||||
readonly icon?: string;
|
readonly icon?: string;
|
||||||
readonly template_version_id: string;
|
readonly template_version_id: string;
|
||||||
readonly default_ttl_ms?: number;
|
readonly default_ttl_ms?: number;
|
||||||
|
readonly activity_bump_ms?: number;
|
||||||
readonly max_ttl_ms?: number;
|
readonly max_ttl_ms?: number;
|
||||||
readonly autostop_requirement?: TemplateAutostopRequirement;
|
readonly autostop_requirement?: TemplateAutostopRequirement;
|
||||||
readonly autostart_requirement?: TemplateAutostartRequirement;
|
readonly autostart_requirement?: TemplateAutostartRequirement;
|
||||||
|
@ -1028,6 +1029,7 @@ export interface Template {
|
||||||
readonly deprecation_message: string;
|
readonly deprecation_message: string;
|
||||||
readonly icon: string;
|
readonly icon: string;
|
||||||
readonly default_ttl_ms: number;
|
readonly default_ttl_ms: number;
|
||||||
|
readonly activity_bump_ms: number;
|
||||||
readonly use_max_ttl: boolean;
|
readonly use_max_ttl: boolean;
|
||||||
readonly max_ttl_ms: number;
|
readonly max_ttl_ms: number;
|
||||||
readonly autostop_requirement: TemplateAutostopRequirement;
|
readonly autostop_requirement: TemplateAutostopRequirement;
|
||||||
|
@ -1285,6 +1287,7 @@ export interface UpdateTemplateMeta {
|
||||||
readonly description?: string;
|
readonly description?: string;
|
||||||
readonly icon?: string;
|
readonly icon?: string;
|
||||||
readonly default_ttl_ms?: number;
|
readonly default_ttl_ms?: number;
|
||||||
|
readonly activity_bump_ms?: number;
|
||||||
readonly max_ttl_ms?: number;
|
readonly max_ttl_ms?: number;
|
||||||
readonly autostop_requirement?: TemplateAutostopRequirement;
|
readonly autostop_requirement?: TemplateAutostopRequirement;
|
||||||
readonly autostart_requirement?: TemplateAutostartRequirement;
|
readonly autostart_requirement?: TemplateAutostartRequirement;
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { TemplateSettingsPage } from "./TemplateSettingsPage";
|
||||||
type FormValues = Required<
|
type FormValues = Required<
|
||||||
Omit<
|
Omit<
|
||||||
UpdateTemplateMeta,
|
UpdateTemplateMeta,
|
||||||
"default_ttl_ms" | "max_ttl_ms" | "deprecation_message"
|
"default_ttl_ms" | "activity_bump_ms" | "max_ttl_ms" | "deprecation_message"
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,33 @@ export const DefaultTTLHelperText = (props: { ttl?: number }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
Workspaces will default to stopping after {ttl} {hours(ttl)}. This will be
|
Workspaces will default to stopping after {ttl} {hours(ttl)} after being
|
||||||
extended by 1 hour after last activity in the workspace was detected.
|
started.
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ActivityBumpHelperText = (props: { bump?: number }) => {
|
||||||
|
const { bump = 0 } = props;
|
||||||
|
|
||||||
|
// Error will show once field is considered touched
|
||||||
|
if (bump < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bump === 0) {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
Workspaces will not have their stop time automatically extended based on
|
||||||
|
user activity. Users can still manually delay the stop time.
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
Workspaces will be automatically bumped by {bump} {hours(bump)} when user
|
||||||
|
activity is detected.
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {
|
||||||
} from "./useWorkspacesToBeDeleted";
|
} from "./useWorkspacesToBeDeleted";
|
||||||
import { TemplateScheduleFormValues, getValidationSchema } from "./formHelpers";
|
import { TemplateScheduleFormValues, getValidationSchema } from "./formHelpers";
|
||||||
import {
|
import {
|
||||||
|
ActivityBumpHelperText,
|
||||||
DefaultTTLHelperText,
|
DefaultTTLHelperText,
|
||||||
DormancyAutoDeletionTTLHelperText,
|
DormancyAutoDeletionTTLHelperText,
|
||||||
DormancyTTLHelperText,
|
DormancyTTLHelperText,
|
||||||
|
@ -72,6 +73,7 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
// on display, convert from ms => hours
|
// on display, convert from ms => hours
|
||||||
default_ttl_ms: template.default_ttl_ms / MS_HOUR_CONVERSION,
|
default_ttl_ms: template.default_ttl_ms / MS_HOUR_CONVERSION,
|
||||||
|
activity_bump_ms: template.activity_bump_ms / MS_HOUR_CONVERSION,
|
||||||
// the API ignores these values, but to avoid tripping up validation set
|
// the API ignores these values, but to avoid tripping up validation set
|
||||||
// it to zero if the user can't set the field.
|
// it to zero if the user can't set the field.
|
||||||
use_max_ttl:
|
use_max_ttl:
|
||||||
|
@ -206,6 +208,9 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||||
default_ttl_ms: form.values.default_ttl_ms
|
default_ttl_ms: form.values.default_ttl_ms
|
||||||
? form.values.default_ttl_ms * MS_HOUR_CONVERSION
|
? form.values.default_ttl_ms * MS_HOUR_CONVERSION
|
||||||
: undefined,
|
: undefined,
|
||||||
|
activity_bump_ms: form.values.activity_bump_ms
|
||||||
|
? form.values.activity_bump_ms * MS_HOUR_CONVERSION
|
||||||
|
: undefined,
|
||||||
max_ttl_ms:
|
max_ttl_ms:
|
||||||
form.values.max_ttl_ms && form.values.use_max_ttl
|
form.values.max_ttl_ms && form.values.use_max_ttl
|
||||||
? form.values.max_ttl_ms * MS_HOUR_CONVERSION
|
? form.values.max_ttl_ms * MS_HOUR_CONVERSION
|
||||||
|
@ -365,6 +370,19 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||||
label="Default autostop (hours)"
|
label="Default autostop (hours)"
|
||||||
type="number"
|
type="number"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
{...getFieldHelpers("activity_bump_ms", {
|
||||||
|
helperText: (
|
||||||
|
<ActivityBumpHelperText bump={form.values.activity_bump_ms} />
|
||||||
|
),
|
||||||
|
})}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
fullWidth
|
||||||
|
inputProps={{ min: 0, step: 1 }}
|
||||||
|
label="Activity bump (hours)"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import TemplateSchedulePage from "./TemplateSchedulePage";
|
||||||
|
|
||||||
const validFormValues: TemplateScheduleFormValues = {
|
const validFormValues: TemplateScheduleFormValues = {
|
||||||
default_ttl_ms: 1,
|
default_ttl_ms: 1,
|
||||||
|
activity_bump_ms: 1,
|
||||||
use_max_ttl: true,
|
use_max_ttl: true,
|
||||||
max_ttl_ms: 2,
|
max_ttl_ms: 2,
|
||||||
failure_ttl_ms: 7,
|
failure_ttl_ms: 7,
|
||||||
|
|
|
@ -25,19 +25,31 @@ export const getValidationSchema = (): Yup.AnyObjectSchema =>
|
||||||
Yup.object({
|
Yup.object({
|
||||||
default_ttl_ms: Yup.number()
|
default_ttl_ms: Yup.number()
|
||||||
.integer()
|
.integer()
|
||||||
|
.required()
|
||||||
.min(0, "Default time until autostop must not be less than 0.")
|
.min(0, "Default time until autostop must not be less than 0.")
|
||||||
.max(
|
.max(
|
||||||
24 * MAX_TTL_DAYS /* 30 days in hours */,
|
24 * MAX_TTL_DAYS /* 30 days in hours */,
|
||||||
"Please enter a limit that is less than or equal to 720 hours (30 days).",
|
"Please enter a limit that is less than or equal to 720 hours (30 days).",
|
||||||
),
|
),
|
||||||
|
activity_bump_ms: Yup.number()
|
||||||
|
.integer()
|
||||||
|
.required()
|
||||||
|
.min(0, "Activity bump must not be less than 0.")
|
||||||
|
.max(
|
||||||
|
24 * MAX_TTL_DAYS /* 30 days in hours */,
|
||||||
|
"Please enter an activity bump duration that is less than or equal to 720 hours (30 days).",
|
||||||
|
),
|
||||||
max_ttl_ms: Yup.number()
|
max_ttl_ms: Yup.number()
|
||||||
.integer()
|
.integer()
|
||||||
|
.required()
|
||||||
.min(0, "Maximum time until autostop must not be less than 0.")
|
.min(0, "Maximum time until autostop must not be less than 0.")
|
||||||
.max(
|
.max(
|
||||||
24 * MAX_TTL_DAYS /* 30 days in hours */,
|
24 * MAX_TTL_DAYS /* 30 days in hours */,
|
||||||
"Please enter a limit that is less than or equal to 720 hours (30 days).",
|
"Please enter a limit that is less than or equal to 720 hours (30 days).",
|
||||||
),
|
),
|
||||||
failure_ttl_ms: Yup.number()
|
failure_ttl_ms: Yup.number()
|
||||||
|
.integer()
|
||||||
|
.required()
|
||||||
.min(0, "Failure cleanup days must not be less than 0.")
|
.min(0, "Failure cleanup days must not be less than 0.")
|
||||||
.test(
|
.test(
|
||||||
"positive-if-enabled",
|
"positive-if-enabled",
|
||||||
|
@ -52,6 +64,8 @@ export const getValidationSchema = (): Yup.AnyObjectSchema =>
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
time_til_dormant_ms: Yup.number()
|
time_til_dormant_ms: Yup.number()
|
||||||
|
.integer()
|
||||||
|
.required()
|
||||||
.min(0, "Dormancy threshold days must not be less than 0.")
|
.min(0, "Dormancy threshold days must not be less than 0.")
|
||||||
.test(
|
.test(
|
||||||
"positive-if-enabled",
|
"positive-if-enabled",
|
||||||
|
@ -66,6 +80,8 @@ export const getValidationSchema = (): Yup.AnyObjectSchema =>
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
time_til_dormant_autodelete_ms: Yup.number()
|
time_til_dormant_autodelete_ms: Yup.number()
|
||||||
|
.integer()
|
||||||
|
.required()
|
||||||
.min(0, "Dormancy auto-deletion days must not be less than 0.")
|
.min(0, "Dormancy auto-deletion days must not be less than 0.")
|
||||||
.test(
|
.test(
|
||||||
"positive-if-enabled",
|
"positive-if-enabled",
|
||||||
|
|
|
@ -459,6 +459,7 @@ export const MockTemplate: TypesGen.Template = {
|
||||||
},
|
},
|
||||||
description: "This is a test description.",
|
description: "This is a test description.",
|
||||||
default_ttl_ms: 24 * 60 * 60 * 1000,
|
default_ttl_ms: 24 * 60 * 60 * 1000,
|
||||||
|
activity_bump_ms: 1 * 60 * 60 * 1000,
|
||||||
use_max_ttl: false,
|
use_max_ttl: false,
|
||||||
max_ttl_ms: 0,
|
max_ttl_ms: 0,
|
||||||
autostop_requirement: {
|
autostop_requirement: {
|
||||||
|
|
Loading…
Reference in New Issue