mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add template activity_bump property (#11734)
Allows template admins to configure the activity bump duration. Defaults to 1h.
This commit is contained in:
@@ -41,6 +41,7 @@ func Test_ActivityBumpWorkspace(t *testing.T) {
|
||||
maxDeadlineOffset *time.Duration
|
||||
workspaceTTL time.Duration
|
||||
templateTTL time.Duration
|
||||
templateActivityBump time.Duration
|
||||
templateDisallowsUserAutostop bool
|
||||
expectedBump time.Duration
|
||||
// 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),
|
||||
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
|
||||
for _, tz := range timezones {
|
||||
@@ -186,11 +207,19 @@ func Test_ActivityBumpWorkspace(t *testing.T) {
|
||||
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{
|
||||
ID: template.ID,
|
||||
UpdatedAt: dbtime.Now(),
|
||||
AllowUserAutostop: !tt.templateDisallowsUserAutostop,
|
||||
DefaultTTL: int64(tt.templateTTL),
|
||||
ActivityBump: int64(activityBump),
|
||||
}), "unexpected error updating template schedule")
|
||||
|
||||
var buildNumber int32 = 1
|
||||
|
||||
Generated
+7
@@ -8536,6 +8536,10 @@ const docTemplate = `{
|
||||
"template_version_id"
|
||||
],
|
||||
"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": {
|
||||
"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"
|
||||
@@ -10954,6 +10958,9 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"activity_bump_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"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.",
|
||||
"type": "boolean"
|
||||
|
||||
Generated
+7
@@ -7609,6 +7609,10 @@
|
||||
"type": "object",
|
||||
"required": ["name", "template_version_id"],
|
||||
"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": {
|
||||
"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"
|
||||
@@ -9896,6 +9900,9 @@
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"activity_bump_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"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.",
|
||||
"type": "boolean"
|
||||
|
||||
@@ -841,10 +841,14 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, arg database.Ac
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if template.ActivityBump == 0 {
|
||||
return nil
|
||||
}
|
||||
activityBump := time.Duration(template.ActivityBump)
|
||||
|
||||
var ttlDur time.Duration
|
||||
if now.Add(time.Hour).After(arg.NextAutostart) && arg.NextAutostart.After(now) {
|
||||
// Extend to TTL
|
||||
if now.Add(activityBump).After(arg.NextAutostart) && arg.NextAutostart.After(now) {
|
||||
// Extend to TTL (NOT activity bump)
|
||||
add := arg.NextAutostart.Sub(now)
|
||||
if workspace.Ttl.Valid && template.AllowUserAutostop {
|
||||
add += time.Duration(workspace.Ttl.Int64)
|
||||
@@ -853,7 +857,8 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, arg database.Ac
|
||||
}
|
||||
ttlDur = add
|
||||
} else {
|
||||
ttlDur = time.Hour
|
||||
// Otherwise, default to regular activity bump duration.
|
||||
ttlDur = activityBump
|
||||
}
|
||||
|
||||
// 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.UpdatedAt = dbtime.Now()
|
||||
tpl.DefaultTTL = arg.DefaultTTL
|
||||
tpl.ActivityBump = arg.ActivityBump
|
||||
tpl.UseMaxTtl = arg.UseMaxTtl
|
||||
tpl.MaxTTL = arg.MaxTTL
|
||||
tpl.AutostopRequirementDaysOfWeek = arg.AutostopRequirementDaysOfWeek
|
||||
|
||||
Generated
+3
-1
@@ -849,7 +849,8 @@ CREATE TABLE templates (
|
||||
autostart_block_days_of_week smallint DEFAULT 0 NOT NULL,
|
||||
require_active_version boolean DEFAULT false 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.';
|
||||
@@ -899,6 +900,7 @@ CREATE VIEW template_with_users AS
|
||||
templates.require_active_version,
|
||||
templates.deprecated,
|
||||
templates.use_max_ttl,
|
||||
templates.activity_bump,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username
|
||||
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.Deprecated,
|
||||
&i.UseMaxTtl,
|
||||
&i.ActivityBump,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
|
||||
@@ -2003,6 +2003,7 @@ type Template struct {
|
||||
RequireActiveVersion bool `db:"require_active_version" json:"require_active_version"`
|
||||
Deprecated string `db:"deprecated" json:"deprecated"`
|
||||
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"`
|
||||
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"`
|
||||
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.
|
||||
Deprecated string `db:"deprecated" json:"deprecated"`
|
||||
UseMaxTtl bool `db:"use_max_ttl" json:"use_max_ttl"`
|
||||
Deprecated string `db:"deprecated" json:"deprecated"`
|
||||
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.
|
||||
|
||||
@@ -24,12 +24,14 @@ type sqlcQuerier interface {
|
||||
// multiple provisioners from acquiring the same jobs. See:
|
||||
// https://www.postgresql.org/docs/9.5/sql-select.html#SQL-FOR-UPDATE-SHARE
|
||||
AcquireProvisionerJob(ctx context.Context, arg AcquireProvisionerJobParams) (ProvisionerJob, error)
|
||||
// Bumps the workspace deadline by 1 hour. If the workspace bump will
|
||||
// cross an autostart threshold, then the bump is autostart + TTL. This
|
||||
// is the deadline behavior if the workspace was to autostart from a stopped
|
||||
// state.
|
||||
// Max deadline is respected, and will never be bumped.
|
||||
// Bumps the workspace deadline by the template's configured "activity_bump"
|
||||
// duration (default 1h). If the workspace bump will cross an autostart
|
||||
// threshold, then the bump is autostart + TTL. This is the deadline behavior if
|
||||
// the workspace was to autostart from a stopped state.
|
||||
//
|
||||
// Max deadline is respected, and the deadline will never be bumped past it.
|
||||
// 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 workspace shutdown is manual.
|
||||
// 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.transition AS build_transition,
|
||||
provisioner_jobs.completed_at::timestamp with time zone AS job_completed_at,
|
||||
templates.activity_bump AS activity_bump,
|
||||
(
|
||||
CASE
|
||||
-- If the extension would push us over the next_autostart
|
||||
-- interval, then extend the deadline by the full ttl from
|
||||
-- the autostart time. This will essentially be as if the
|
||||
-- workspace auto started at the given time and the original
|
||||
-- TTL was applied.
|
||||
WHEN NOW() + ('60 minutes')::interval > $1 :: timestamptz
|
||||
-- interval, then extend the deadline by the full TTL (NOT
|
||||
-- activity bump) from the autostart time. This will essentially
|
||||
-- be as if the workspace auto started at the given time and the
|
||||
-- original TTL was applied.
|
||||
--
|
||||
-- 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
|
||||
-- autostart schedule is either the 0 time and not provided,
|
||||
-- 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.
|
||||
AND $1 > NOW()
|
||||
THEN
|
||||
-- Extend to the autostart, then add the TTL
|
||||
-- Extend to the autostart, then add the activity bump
|
||||
(($1 :: timestamptz) - NOW()) + CASE
|
||||
WHEN templates.allow_user_autostop
|
||||
THEN (workspaces.ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||
ELSE (templates.default_ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||
END
|
||||
|
||||
-- Default to 60 minutes.
|
||||
-- Default to the activity bump duration.
|
||||
ELSE
|
||||
('60 minutes')::interval
|
||||
(templates.activity_bump / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||
END
|
||||
) AS ttl_interval
|
||||
FROM workspace_builds
|
||||
@@ -74,6 +79,7 @@ SET
|
||||
FROM latest l
|
||||
WHERE wb.id = l.build_id
|
||||
AND l.job_completed_at IS NOT NULL
|
||||
AND l.activity_bump > 0
|
||||
AND l.build_transition = 'start'
|
||||
AND l.ttl_interval > '0 seconds'::interval
|
||||
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"`
|
||||
}
|
||||
|
||||
// Bumps the workspace deadline by 1 hour. If the workspace bump will
|
||||
// cross an autostart threshold, then the bump is autostart + TTL. This
|
||||
// is the deadline behavior if the workspace was to autostart from a stopped
|
||||
// state.
|
||||
// Max deadline is respected, and will never be bumped.
|
||||
// Bumps the workspace deadline by the template's configured "activity_bump"
|
||||
// duration (default 1h). If the workspace bump will cross an autostart
|
||||
// threshold, then the bump is autostart + TTL. This is the deadline behavior if
|
||||
// the workspace was to autostart from a stopped state.
|
||||
//
|
||||
// Max deadline is respected, and the deadline will never be bumped past it.
|
||||
// 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 workspace shutdown is manual.
|
||||
// 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
|
||||
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
|
||||
template_with_users
|
||||
WHERE
|
||||
@@ -5761,6 +5769,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
&i.RequireActiveVersion,
|
||||
&i.Deprecated,
|
||||
&i.UseMaxTtl,
|
||||
&i.ActivityBump,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
)
|
||||
@@ -5769,7 +5778,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
|
||||
const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, 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
|
||||
template_with_users AS templates
|
||||
WHERE
|
||||
@@ -5818,6 +5827,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
&i.RequireActiveVersion,
|
||||
&i.Deprecated,
|
||||
&i.UseMaxTtl,
|
||||
&i.ActivityBump,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
)
|
||||
@@ -5825,7 +5835,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
}
|
||||
|
||||
const getTemplates = `-- name: GetTemplates :many
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, 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
|
||||
`
|
||||
|
||||
@@ -5867,6 +5877,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
&i.RequireActiveVersion,
|
||||
&i.Deprecated,
|
||||
&i.UseMaxTtl,
|
||||
&i.ActivityBump,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
@@ -5885,7 +5896,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
|
||||
const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, 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
|
||||
template_with_users AS templates
|
||||
WHERE
|
||||
@@ -5977,6 +5988,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||
&i.RequireActiveVersion,
|
||||
&i.Deprecated,
|
||||
&i.UseMaxTtl,
|
||||
&i.ActivityBump,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
); err != nil {
|
||||
@@ -6184,14 +6196,15 @@ SET
|
||||
allow_user_autostart = $3,
|
||||
allow_user_autostop = $4,
|
||||
default_ttl = $5,
|
||||
use_max_ttl = $6,
|
||||
max_ttl = $7,
|
||||
autostop_requirement_days_of_week = $8,
|
||||
autostop_requirement_weeks = $9,
|
||||
autostart_block_days_of_week = $10,
|
||||
failure_ttl = $11,
|
||||
time_til_dormant = $12,
|
||||
time_til_dormant_autodelete = $13
|
||||
activity_bump = $6,
|
||||
use_max_ttl = $7,
|
||||
max_ttl = $8,
|
||||
autostop_requirement_days_of_week = $9,
|
||||
autostop_requirement_weeks = $10,
|
||||
autostart_block_days_of_week = $11,
|
||||
failure_ttl = $12,
|
||||
time_til_dormant = $13,
|
||||
time_til_dormant_autodelete = $14
|
||||
WHERE
|
||||
id = $1
|
||||
`
|
||||
@@ -6202,6 +6215,7 @@ type UpdateTemplateScheduleByIDParams struct {
|
||||
AllowUserAutostart bool `db:"allow_user_autostart" json:"allow_user_autostart"`
|
||||
AllowUserAutostop bool `db:"allow_user_autostop" json:"allow_user_autostop"`
|
||||
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"`
|
||||
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
|
||||
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.AllowUserAutostop,
|
||||
arg.DefaultTTL,
|
||||
arg.ActivityBump,
|
||||
arg.UseMaxTtl,
|
||||
arg.MaxTTL,
|
||||
arg.AutostopRequirementDaysOfWeek,
|
||||
@@ -11363,7 +11378,7 @@ LEFT JOIN LATERAL (
|
||||
) latest_build ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
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
|
||||
templates
|
||||
WHERE
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
-- Bumps the workspace deadline by 1 hour. If the workspace bump will
|
||||
-- cross an autostart threshold, then the bump is autostart + TTL. This
|
||||
-- is the deadline behavior if the workspace was to autostart from a stopped
|
||||
-- state.
|
||||
-- Max deadline is respected, and will never be bumped.
|
||||
-- Bumps the workspace deadline by the template's configured "activity_bump"
|
||||
-- duration (default 1h). If the workspace bump will cross an autostart
|
||||
-- threshold, then the bump is autostart + TTL. This is the deadline behavior if
|
||||
-- the workspace was to autostart from a stopped state.
|
||||
--
|
||||
-- Max deadline is respected, and the deadline will never be bumped past it.
|
||||
-- The deadline will never decrease.
|
||||
-- name: ActivityBumpWorkspace :exec
|
||||
WITH latest AS (
|
||||
@@ -12,14 +13,19 @@ WITH latest AS (
|
||||
workspace_builds.max_deadline::timestamp with time zone AS build_max_deadline,
|
||||
workspace_builds.transition AS build_transition,
|
||||
provisioner_jobs.completed_at::timestamp with time zone AS job_completed_at,
|
||||
templates.activity_bump AS activity_bump,
|
||||
(
|
||||
CASE
|
||||
-- If the extension would push us over the next_autostart
|
||||
-- interval, then extend the deadline by the full ttl from
|
||||
-- the autostart time. This will essentially be as if the
|
||||
-- workspace auto started at the given time and the original
|
||||
-- TTL was applied.
|
||||
WHEN NOW() + ('60 minutes')::interval > @next_autostart :: timestamptz
|
||||
-- interval, then extend the deadline by the full TTL (NOT
|
||||
-- activity bump) from the autostart time. This will essentially
|
||||
-- be as if the workspace auto started at the given time and the
|
||||
-- original TTL was applied.
|
||||
--
|
||||
-- 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
|
||||
-- autostart schedule is either the 0 time and not provided,
|
||||
-- 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.
|
||||
AND @next_autostart > NOW()
|
||||
THEN
|
||||
-- Extend to the autostart, then add the TTL
|
||||
-- Extend to the autostart, then add the activity bump
|
||||
((@next_autostart :: timestamptz) - NOW()) + CASE
|
||||
WHEN templates.allow_user_autostop
|
||||
THEN (workspaces.ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||
ELSE (templates.default_ttl / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||
END
|
||||
|
||||
-- Default to 60 minutes.
|
||||
-- Default to the activity bump duration.
|
||||
ELSE
|
||||
('60 minutes')::interval
|
||||
(templates.activity_bump / 1000 / 1000 / 1000 || ' seconds')::interval
|
||||
END
|
||||
) AS ttl_interval
|
||||
FROM workspace_builds
|
||||
@@ -63,6 +69,8 @@ SET
|
||||
FROM latest l
|
||||
WHERE wb.id = l.build_id
|
||||
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'
|
||||
-- We only bump if the raw interval is positive and non-zero.
|
||||
AND l.ttl_interval > '0 seconds'::interval
|
||||
|
||||
@@ -129,14 +129,15 @@ SET
|
||||
allow_user_autostart = $3,
|
||||
allow_user_autostop = $4,
|
||||
default_ttl = $5,
|
||||
use_max_ttl = $6,
|
||||
max_ttl = $7,
|
||||
autostop_requirement_days_of_week = $8,
|
||||
autostop_requirement_weeks = $9,
|
||||
autostart_block_days_of_week = $10,
|
||||
failure_ttl = $11,
|
||||
time_til_dormant = $12,
|
||||
time_til_dormant_autodelete = $13
|
||||
activity_bump = $6,
|
||||
use_max_ttl = $7,
|
||||
max_ttl = $8,
|
||||
autostop_requirement_days_of_week = $9,
|
||||
autostop_requirement_weeks = $10,
|
||||
autostart_block_days_of_week = $11,
|
||||
failure_ttl = $12,
|
||||
time_til_dormant = $13,
|
||||
time_til_dormant_autodelete = $14
|
||||
WHERE
|
||||
id = $1
|
||||
;
|
||||
|
||||
@@ -117,7 +117,10 @@ type TemplateScheduleOptions struct {
|
||||
UserAutostartEnabled bool `json:"user_autostart_enabled"`
|
||||
UserAutostopEnabled bool `json:"user_autostop_enabled"`
|
||||
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
|
||||
// autostop_requirement for this template. This is governed by the template
|
||||
// and licensing.
|
||||
@@ -181,6 +184,7 @@ func (*agplTemplateScheduleStore) Get(ctx context.Context, db database.Store, te
|
||||
UserAutostartEnabled: true,
|
||||
UserAutostopEnabled: true,
|
||||
DefaultTTL: time.Duration(tpl.DefaultTTL),
|
||||
ActivityBump: time.Duration(tpl.ActivityBump),
|
||||
// Disregard the values in the database, since AutostopRequirement,
|
||||
// FailureTTL, TimeTilDormant, and TimeTilDormantAutoDelete are enterprise features.
|
||||
UseMaxTTL: false,
|
||||
@@ -205,7 +209,7 @@ func (*agplTemplateScheduleStore) Set(ctx context.Context, db database.Store, tp
|
||||
ctx, span := tracing.StartSpan(ctx)
|
||||
defer span.End()
|
||||
|
||||
if int64(opts.DefaultTTL) == tpl.DefaultTTL {
|
||||
if int64(opts.DefaultTTL) == tpl.DefaultTTL && int64(opts.ActivityBump) == tpl.ActivityBump {
|
||||
// Avoid updating the UpdatedAt timestamp if nothing will be changed.
|
||||
return tpl, nil
|
||||
}
|
||||
@@ -213,9 +217,10 @@ func (*agplTemplateScheduleStore) Set(ctx context.Context, db database.Store, tp
|
||||
var template database.Template
|
||||
err := db.InTx(func(db database.Store) error {
|
||||
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
|
||||
ID: tpl.ID,
|
||||
UpdatedAt: dbtime.Now(),
|
||||
DefaultTTL: int64(opts.DefaultTTL),
|
||||
ID: tpl.ID,
|
||||
UpdatedAt: dbtime.Now(),
|
||||
DefaultTTL: int64(opts.DefaultTTL),
|
||||
ActivityBump: int64(opts.ActivityBump),
|
||||
// Don't allow changing these settings, but keep the value in the DB (to
|
||||
// avoid clearing settings if the license has an issue).
|
||||
UseMaxTtl: tpl.UseMaxTtl,
|
||||
|
||||
+17
-3
@@ -224,6 +224,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
|
||||
var (
|
||||
defaultTTL time.Duration
|
||||
activityBump = time.Hour // default
|
||||
maxTTL time.Duration
|
||||
autostopRequirementDaysOfWeek []string
|
||||
autostartRequirementDaysOfWeek []string
|
||||
@@ -235,6 +236,9 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
if createTemplate.DefaultTTLMillis != nil {
|
||||
defaultTTL = time.Duration(*createTemplate.DefaultTTLMillis) * time.Millisecond
|
||||
}
|
||||
if createTemplate.ActivityBumpMillis != nil {
|
||||
activityBump = time.Duration(*createTemplate.ActivityBumpMillis) * time.Millisecond
|
||||
}
|
||||
if createTemplate.AutostopRequirement != nil {
|
||||
autostopRequirementDaysOfWeek = createTemplate.AutostopRequirement.DaysOfWeek
|
||||
autostopRequirementWeeks = createTemplate.AutostopRequirement.Weeks
|
||||
@@ -263,6 +267,9 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
if defaultTTL < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
if activityBump < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "activity_bump_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
if maxTTL < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
@@ -313,7 +320,6 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
|
||||
var (
|
||||
dbTemplate database.Template
|
||||
template codersdk.Template
|
||||
|
||||
allowUserCancelWorkspaceJobs = ptr.NilToDefault(createTemplate.AllowUserCancelWorkspaceJobs, false)
|
||||
allowUserAutostart = ptr.NilToDefault(createTemplate.AllowUserAutostart, true)
|
||||
@@ -368,6 +374,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
UserAutostopEnabled: allowUserAutostop,
|
||||
UseMaxTTL: maxTTL > 0,
|
||||
DefaultTTL: defaultTTL,
|
||||
ActivityBump: activityBump,
|
||||
MaxTTL: maxTTL,
|
||||
// Some of these values are enterprise-only, but the
|
||||
// TemplateScheduleStore will handle avoiding setting them if
|
||||
@@ -409,7 +416,6 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
templateVersionAudit.New = newTemplateVersion
|
||||
|
||||
template = api.convertTemplate(dbTemplate)
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
@@ -425,7 +431,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
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
|
||||
@@ -565,6 +571,9 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
if req.DefaultTTLMillis < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
if req.ActivityBumpMillis < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "activity_bump_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
if req.MaxTTLMillis < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
@@ -648,6 +657,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
req.AllowUserAutostop == template.AllowUserAutostop &&
|
||||
req.AllowUserCancelWorkspaceJobs == template.AllowUserCancelWorkspaceJobs &&
|
||||
req.DefaultTTLMillis == time.Duration(template.DefaultTTL).Milliseconds() &&
|
||||
req.ActivityBumpMillis == time.Duration(template.ActivityBump).Milliseconds() &&
|
||||
useMaxTTL == scheduleOpts.UseMaxTTL &&
|
||||
req.MaxTTLMillis == time.Duration(template.MaxTTL).Milliseconds() &&
|
||||
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
|
||||
activityBump := time.Duration(req.ActivityBumpMillis) * time.Millisecond
|
||||
maxTTL := time.Duration(req.MaxTTLMillis) * time.Millisecond
|
||||
failureTTL := time.Duration(req.FailureTTLMillis) * time.Millisecond
|
||||
inactivityTTL := time.Duration(req.TimeTilDormantMillis) * time.Millisecond
|
||||
timeTilDormantAutoDelete := time.Duration(req.TimeTilDormantAutoDeleteMillis) * time.Millisecond
|
||||
|
||||
if defaultTTL != time.Duration(template.DefaultTTL) ||
|
||||
activityBump != time.Duration(template.ActivityBump) ||
|
||||
useMaxTTL != scheduleOpts.UseMaxTTL ||
|
||||
maxTTL != time.Duration(template.MaxTTL) ||
|
||||
autostopRequirementDaysOfWeekParsed != scheduleOpts.AutostopRequirement.DaysOfWeek ||
|
||||
@@ -726,6 +738,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
UserAutostartEnabled: req.AllowUserAutostart,
|
||||
UserAutostopEnabled: req.AllowUserAutostop,
|
||||
DefaultTTL: defaultTTL,
|
||||
ActivityBump: activityBump,
|
||||
UseMaxTTL: useMaxTTL,
|
||||
MaxTTL: maxTTL,
|
||||
AutostopRequirement: schedule.TemplateAutostopRequirement{
|
||||
@@ -875,6 +888,7 @@ func (api *API) convertTemplate(
|
||||
Description: template.Description,
|
||||
Icon: template.Icon,
|
||||
DefaultTTLMillis: time.Duration(template.DefaultTTL).Milliseconds(),
|
||||
ActivityBumpMillis: time.Duration(template.ActivityBump).Milliseconds(),
|
||||
UseMaxTTL: template.UseMaxTtl,
|
||||
MaxTTLMillis: time.Duration(template.MaxTTL).Milliseconds(),
|
||||
CreatedByID: template.CreatedBy,
|
||||
|
||||
@@ -57,7 +57,10 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||
|
||||
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)
|
||||
defer cancel()
|
||||
@@ -67,6 +70,7 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||
|
||||
assert.Equal(t, expected.Name, got.Name)
|
||||
assert.Equal(t, expected.Description, got.Description)
|
||||
assert.Equal(t, expected.ActivityBumpMillis, got.ActivityBumpMillis)
|
||||
|
||||
require.Len(t, auditor.AuditLogs(), 3)
|
||||
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[0].Action)
|
||||
@@ -268,6 +272,7 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||
AllowUserAutostart: options.UserAutostartEnabled,
|
||||
AllowUserAutostop: options.UserAutostopEnabled,
|
||||
DefaultTTL: int64(options.DefaultTTL),
|
||||
ActivityBump: int64(options.ActivityBump),
|
||||
UseMaxTtl: options.UseMaxTTL,
|
||||
MaxTTL: int64(options.MaxTTL),
|
||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||
@@ -320,6 +325,7 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||
AllowUserAutostart: options.UserAutostartEnabled,
|
||||
AllowUserAutostop: options.UserAutostopEnabled,
|
||||
DefaultTTL: int64(options.DefaultTTL),
|
||||
ActivityBump: int64(options.ActivityBump),
|
||||
UseMaxTtl: options.UseMaxTTL,
|
||||
MaxTTL: int64(options.MaxTTL),
|
||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||
@@ -508,6 +514,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
assert.Equal(t, (1 * time.Hour).Milliseconds(), template.ActivityBumpMillis)
|
||||
|
||||
req := codersdk.UpdateTemplateMeta{
|
||||
Name: "new-template-name",
|
||||
@@ -515,6 +522,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
Description: "lorem ipsum dolor sit amet et cetera",
|
||||
Icon: "/icon/new-icon.png",
|
||||
DefaultTTLMillis: 12 * time.Hour.Milliseconds(),
|
||||
ActivityBumpMillis: 3 * time.Hour.Milliseconds(),
|
||||
AllowUserCancelWorkspaceJobs: false,
|
||||
}
|
||||
// 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.Icon, updated.Icon)
|
||||
assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis)
|
||||
assert.Equal(t, req.ActivityBumpMillis, updated.ActivityBumpMillis)
|
||||
assert.False(t, req.AllowUserCancelWorkspaceJobs)
|
||||
|
||||
// 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.Icon, updated.Icon)
|
||||
assert.Equal(t, req.DefaultTTLMillis, updated.DefaultTTLMillis)
|
||||
assert.Equal(t, req.ActivityBumpMillis, updated.ActivityBumpMillis)
|
||||
assert.False(t, req.AllowUserCancelWorkspaceJobs)
|
||||
|
||||
require.Len(t, auditor.AuditLogs(), 5)
|
||||
@@ -707,6 +717,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
AllowUserAutostart: options.UserAutostartEnabled,
|
||||
AllowUserAutostop: options.UserAutostopEnabled,
|
||||
DefaultTTL: int64(options.DefaultTTL),
|
||||
ActivityBump: int64(options.ActivityBump),
|
||||
MaxTTL: int64(options.MaxTTL),
|
||||
UseMaxTtl: options.UseMaxTTL,
|
||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||
@@ -1015,6 +1026,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
Description: template.Description,
|
||||
Icon: template.Icon,
|
||||
DefaultTTLMillis: template.DefaultTTLMillis,
|
||||
ActivityBumpMillis: template.ActivityBumpMillis,
|
||||
AutostopRequirement: nil,
|
||||
AllowUserAutostart: template.AllowUserAutostart,
|
||||
AllowUserAutostop: template.AllowUserAutostop,
|
||||
@@ -1105,6 +1117,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
AllowUserAutostart: options.UserAutostartEnabled,
|
||||
AllowUserAutostop: options.UserAutostopEnabled,
|
||||
DefaultTTL: int64(options.DefaultTTL),
|
||||
ActivityBump: int64(options.ActivityBump),
|
||||
UseMaxTtl: options.UseMaxTTL,
|
||||
MaxTTL: int64(options.MaxTTL),
|
||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||
@@ -1177,6 +1190,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
AllowUserAutostart: options.UserAutostartEnabled,
|
||||
AllowUserAutostop: options.UserAutostopEnabled,
|
||||
DefaultTTL: int64(options.DefaultTTL),
|
||||
ActivityBump: int64(options.ActivityBump),
|
||||
UseMaxTtl: options.UseMaxTTL,
|
||||
MaxTTL: int64(options.MaxTTL),
|
||||
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
|
||||
|
||||
Reference in New Issue
Block a user