mirror of
https://github.com/coder/coder.git
synced 2026-09-21 12:44:32 +08:00
feat: add locked TTL field to template meta (#8020)
This commit is contained in:
Generated
+9
-2
@@ -6684,7 +6684,11 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
},
|
||||
"inactivity_ttl_ms": {
|
||||
"description": "InactivityTTLMillis allows optionally specifying the max lifetime before Coder\ndeletes inactive workspaces created from this template.",
|
||||
"description": "InactivityTTLMillis allows optionally specifying the max lifetime before Coder\nlocks inactive workspaces created from this template.",
|
||||
"type": "integer"
|
||||
},
|
||||
"locked_ttl_ms": {
|
||||
"description": "LockedTTL allows optionally specifying the max lifetime before Coder\npermanently deletes locked workspaces created from this template.",
|
||||
"type": "integer"
|
||||
},
|
||||
"max_ttl_ms": {
|
||||
@@ -8500,7 +8504,7 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
},
|
||||
"failure_ttl_ms": {
|
||||
"description": "FailureTTLMillis and InactivityTTLMillis are enterprise-only. Their\nvalues are used if your license is entitled to use the advanced\ntemplate scheduling feature.",
|
||||
"description": "FailureTTLMillis, InactivityTTLMillis, and LockedTTLMillis are enterprise-only. Their\nvalues are used if your license is entitled to use the advanced\ntemplate scheduling feature.",
|
||||
"type": "integer"
|
||||
},
|
||||
"icon": {
|
||||
@@ -8513,6 +8517,9 @@ const docTemplate = `{
|
||||
"inactivity_ttl_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"locked_ttl_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max_ttl_ms": {
|
||||
"description": "MaxTTLMillis is an enterprise feature. It's value is only used if your\nlicense is entitled to use the advanced template scheduling feature.",
|
||||
"type": "integer"
|
||||
|
||||
Generated
+9
-2
@@ -5955,7 +5955,11 @@
|
||||
"type": "string"
|
||||
},
|
||||
"inactivity_ttl_ms": {
|
||||
"description": "InactivityTTLMillis allows optionally specifying the max lifetime before Coder\ndeletes inactive workspaces created from this template.",
|
||||
"description": "InactivityTTLMillis allows optionally specifying the max lifetime before Coder\nlocks inactive workspaces created from this template.",
|
||||
"type": "integer"
|
||||
},
|
||||
"locked_ttl_ms": {
|
||||
"description": "LockedTTL allows optionally specifying the max lifetime before Coder\npermanently deletes locked workspaces created from this template.",
|
||||
"type": "integer"
|
||||
},
|
||||
"max_ttl_ms": {
|
||||
@@ -7657,7 +7661,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"failure_ttl_ms": {
|
||||
"description": "FailureTTLMillis and InactivityTTLMillis are enterprise-only. Their\nvalues are used if your license is entitled to use the advanced\ntemplate scheduling feature.",
|
||||
"description": "FailureTTLMillis, InactivityTTLMillis, and LockedTTLMillis are enterprise-only. Their\nvalues are used if your license is entitled to use the advanced\ntemplate scheduling feature.",
|
||||
"type": "integer"
|
||||
},
|
||||
"icon": {
|
||||
@@ -7670,6 +7674,9 @@
|
||||
"inactivity_ttl_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"locked_ttl_ms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"max_ttl_ms": {
|
||||
"description": "MaxTTLMillis is an enterprise feature. It's value is only used if your\nlicense is entitled to use the advanced template scheduling feature.",
|
||||
"type": "integer"
|
||||
|
||||
Generated
+2
-1
@@ -494,7 +494,8 @@ CREATE TABLE templates (
|
||||
allow_user_autostart boolean DEFAULT true NOT NULL,
|
||||
allow_user_autostop boolean DEFAULT true NOT NULL,
|
||||
failure_ttl bigint DEFAULT 0 NOT NULL,
|
||||
inactivity_ttl bigint DEFAULT 0 NOT NULL
|
||||
inactivity_ttl bigint DEFAULT 0 NOT NULL,
|
||||
locked_ttl bigint DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN templates.default_ttl IS 'The default duration for autostop for workspaces created from this template.';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
BEGIN;
|
||||
ALTER TABLE templates DROP COLUMN locked_ttl;
|
||||
COMMIT;
|
||||
@@ -0,0 +1,3 @@
|
||||
BEGIN;
|
||||
ALTER TABLE templates ADD COLUMN locked_ttl BIGINT NOT NULL DEFAULT 0;
|
||||
COMMIT;
|
||||
@@ -54,7 +54,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||
pq.Array(arg.IDs),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, xerrors.Errorf("query context: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Template
|
||||
@@ -82,16 +82,17 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
return nil, xerrors.Errorf("scan: %w", err)
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
return nil, xerrors.Errorf("close: %w", err)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
return nil, xerrors.Errorf("rows err: %w", err)
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
@@ -1561,6 +1561,7 @@ type Template struct {
|
||||
AllowUserAutostop bool `db:"allow_user_autostop" json:"allow_user_autostop"`
|
||||
FailureTTL int64 `db:"failure_ttl" json:"failure_ttl"`
|
||||
InactivityTTL int64 `db:"inactivity_ttl" json:"inactivity_ttl"`
|
||||
LockedTTL int64 `db:"locked_ttl" json:"locked_ttl"`
|
||||
}
|
||||
|
||||
type TemplateVersion struct {
|
||||
|
||||
@@ -3240,7 +3240,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, inactivity_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, inactivity_ttl, locked_ttl
|
||||
FROM
|
||||
templates
|
||||
WHERE
|
||||
@@ -3274,13 +3274,14 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
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, inactivity_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, inactivity_ttl, locked_ttl
|
||||
FROM
|
||||
templates
|
||||
WHERE
|
||||
@@ -3322,12 +3323,13 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
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, inactivity_ttl FROM templates
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, max_ttl, allow_user_autostart, allow_user_autostop, failure_ttl, inactivity_ttl, locked_ttl FROM templates
|
||||
ORDER BY (name, id) ASC
|
||||
`
|
||||
|
||||
@@ -3362,6 +3364,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -3378,7 +3381,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, inactivity_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, inactivity_ttl, locked_ttl
|
||||
FROM
|
||||
templates
|
||||
WHERE
|
||||
@@ -3450,6 +3453,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -3483,7 +3487,7 @@ INSERT INTO
|
||||
allow_user_cancel_workspace_jobs
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, 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, inactivity_ttl
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) RETURNING id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, 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, inactivity_ttl, locked_ttl
|
||||
`
|
||||
|
||||
type InsertTemplateParams struct {
|
||||
@@ -3543,6 +3547,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -3556,7 +3561,7 @@ SET
|
||||
WHERE
|
||||
id = $3
|
||||
RETURNING
|
||||
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, inactivity_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, inactivity_ttl, locked_ttl
|
||||
`
|
||||
|
||||
type UpdateTemplateACLByIDParams struct {
|
||||
@@ -3590,6 +3595,7 @@ func (q *sqlQuerier) UpdateTemplateACLByID(ctx context.Context, arg UpdateTempla
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -3649,7 +3655,7 @@ SET
|
||||
WHERE
|
||||
id = $1
|
||||
RETURNING
|
||||
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, inactivity_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, inactivity_ttl, locked_ttl
|
||||
`
|
||||
|
||||
type UpdateTemplateMetaByIDParams struct {
|
||||
@@ -3695,6 +3701,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -3709,11 +3716,12 @@ SET
|
||||
default_ttl = $5,
|
||||
max_ttl = $6,
|
||||
failure_ttl = $7,
|
||||
inactivity_ttl = $8
|
||||
inactivity_ttl = $8,
|
||||
locked_ttl = $9
|
||||
WHERE
|
||||
id = $1
|
||||
RETURNING
|
||||
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, inactivity_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, inactivity_ttl, locked_ttl
|
||||
`
|
||||
|
||||
type UpdateTemplateScheduleByIDParams struct {
|
||||
@@ -3725,6 +3733,7 @@ type UpdateTemplateScheduleByIDParams struct {
|
||||
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
|
||||
FailureTTL int64 `db:"failure_ttl" json:"failure_ttl"`
|
||||
InactivityTTL int64 `db:"inactivity_ttl" json:"inactivity_ttl"`
|
||||
LockedTTL int64 `db:"locked_ttl" json:"locked_ttl"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateTemplateScheduleByIDParams) (Template, error) {
|
||||
@@ -3737,6 +3746,7 @@ func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateT
|
||||
arg.MaxTTL,
|
||||
arg.FailureTTL,
|
||||
arg.InactivityTTL,
|
||||
arg.LockedTTL,
|
||||
)
|
||||
var i Template
|
||||
err := row.Scan(
|
||||
@@ -3761,6 +3771,7 @@ func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateT
|
||||
&i.AllowUserAutostop,
|
||||
&i.FailureTTL,
|
||||
&i.InactivityTTL,
|
||||
&i.LockedTTL,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
@@ -120,7 +120,8 @@ SET
|
||||
default_ttl = $5,
|
||||
max_ttl = $6,
|
||||
failure_ttl = $7,
|
||||
inactivity_ttl = $8
|
||||
inactivity_ttl = $8,
|
||||
locked_ttl = $9
|
||||
WHERE
|
||||
id = $1
|
||||
RETURNING
|
||||
|
||||
@@ -56,6 +56,7 @@ overrides:
|
||||
failure_ttl: FailureTTL
|
||||
inactivity_ttl: InactivityTTL
|
||||
eof: EOF
|
||||
locked_ttl: LockedTTL
|
||||
|
||||
sql:
|
||||
- schema: "./dump.sql"
|
||||
|
||||
@@ -18,10 +18,12 @@ type TemplateScheduleOptions struct {
|
||||
//
|
||||
// If set, users cannot disable automatic workspace shutdown.
|
||||
MaxTTL time.Duration `json:"max_ttl"`
|
||||
// If FailureTTL is set, all failed workspaces will be stopped automatically after this time has elapsed.
|
||||
// FailureTTL dictates the duration after which failed workspaces will be stopped automatically.
|
||||
FailureTTL time.Duration `json:"failure_ttl"`
|
||||
// If InactivityTTL is set, all inactive workspaces will be deleted automatically after this time has elapsed.
|
||||
// InactivityTTL dictates the duration after which inactive workspaces will be locked.
|
||||
InactivityTTL time.Duration `json:"inactivity_ttl"`
|
||||
// LockedTTL dictates the duration after which locked workspaces will be permanently deleted.
|
||||
LockedTTL time.Duration `json:"locked_ttl"`
|
||||
}
|
||||
|
||||
// TemplateScheduleStore provides an interface for retrieving template
|
||||
@@ -51,11 +53,12 @@ func (*agplTemplateScheduleStore) GetTemplateScheduleOptions(ctx context.Context
|
||||
UserAutostartEnabled: true,
|
||||
UserAutostopEnabled: true,
|
||||
DefaultTTL: time.Duration(tpl.DefaultTTL),
|
||||
// Disregard the values in the database, since MaxTTL, FailureTTL, and InactivityTTL are enterprise
|
||||
// Disregard the values in the database, since MaxTTL, FailureTTL, InactivityTTL, and LockedTTL are enterprise
|
||||
// features.
|
||||
MaxTTL: 0,
|
||||
FailureTTL: 0,
|
||||
InactivityTTL: 0,
|
||||
LockedTTL: 0,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -76,5 +79,6 @@ func (*agplTemplateScheduleStore) SetTemplateScheduleOptions(ctx context.Context
|
||||
MaxTTL: tpl.MaxTTL,
|
||||
FailureTTL: tpl.FailureTTL,
|
||||
InactivityTTL: tpl.InactivityTTL,
|
||||
LockedTTL: tpl.LockedTTL,
|
||||
})
|
||||
}
|
||||
|
||||
+12
-1
@@ -497,6 +497,12 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
if req.InactivityTTLMillis < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "inactivity_ttl_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
if req.InactivityTTLMillis < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "inactivity_ttl_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
if req.LockedTTLMillis < 0 {
|
||||
validErrs = append(validErrs, codersdk.ValidationError{Field: "locked_ttl_ms", Detail: "Must be a positive integer."})
|
||||
}
|
||||
|
||||
if len(validErrs) > 0 {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
@@ -518,7 +524,8 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
req.DefaultTTLMillis == time.Duration(template.DefaultTTL).Milliseconds() &&
|
||||
req.MaxTTLMillis == time.Duration(template.MaxTTL).Milliseconds() &&
|
||||
req.FailureTTLMillis == time.Duration(template.FailureTTL).Milliseconds() &&
|
||||
req.InactivityTTLMillis == time.Duration(template.InactivityTTL).Milliseconds() {
|
||||
req.InactivityTTLMillis == time.Duration(template.InactivityTTL).Milliseconds() &&
|
||||
req.FailureTTLMillis == time.Duration(template.LockedTTL).Milliseconds() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -546,11 +553,13 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
maxTTL := time.Duration(req.MaxTTLMillis) * time.Millisecond
|
||||
failureTTL := time.Duration(req.FailureTTLMillis) * time.Millisecond
|
||||
inactivityTTL := time.Duration(req.InactivityTTLMillis) * time.Millisecond
|
||||
lockedTTL := time.Duration(req.LockedTTLMillis) * time.Millisecond
|
||||
|
||||
if defaultTTL != time.Duration(template.DefaultTTL) ||
|
||||
maxTTL != time.Duration(template.MaxTTL) ||
|
||||
failureTTL != time.Duration(template.FailureTTL) ||
|
||||
inactivityTTL != time.Duration(template.InactivityTTL) ||
|
||||
lockedTTL != time.Duration(template.LockedTTL) ||
|
||||
req.AllowUserAutostart != template.AllowUserAutostart ||
|
||||
req.AllowUserAutostop != template.AllowUserAutostop {
|
||||
updated, err = (*api.TemplateScheduleStore.Load()).SetTemplateScheduleOptions(ctx, tx, updated, schedule.TemplateScheduleOptions{
|
||||
@@ -563,6 +572,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
MaxTTL: maxTTL,
|
||||
FailureTTL: failureTTL,
|
||||
InactivityTTL: inactivityTTL,
|
||||
LockedTTL: lockedTTL,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("set template schedule options: %w", err)
|
||||
@@ -716,5 +726,6 @@ func (api *API) convertTemplate(
|
||||
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
|
||||
FailureTTLMillis: time.Duration(template.FailureTTL).Milliseconds(),
|
||||
InactivityTTLMillis: time.Duration(template.InactivityTTL).Milliseconds(),
|
||||
LockedTTLMillis: time.Duration(template.LockedTTL).Milliseconds(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,6 +635,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
const (
|
||||
failureTTL = 7 * 24 * time.Hour
|
||||
inactivityTTL = 180 * 24 * time.Hour
|
||||
lockedTTL = 360 * 24 * time.Hour
|
||||
)
|
||||
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
@@ -647,9 +648,11 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
if atomic.AddInt64(&setCalled, 1) == 2 {
|
||||
require.Equal(t, failureTTL, options.FailureTTL)
|
||||
require.Equal(t, inactivityTTL, options.InactivityTTL)
|
||||
require.Equal(t, lockedTTL, options.LockedTTL)
|
||||
}
|
||||
template.FailureTTL = int64(options.FailureTTL)
|
||||
template.InactivityTTL = int64(options.InactivityTTL)
|
||||
template.LockedTTL = int64(options.LockedTTL)
|
||||
return template, nil
|
||||
},
|
||||
},
|
||||
@@ -659,6 +662,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
|
||||
ctr.FailureTTLMillis = ptr.Ref(0 * time.Hour.Milliseconds())
|
||||
ctr.InactivityTTLMillis = ptr.Ref(0 * time.Hour.Milliseconds())
|
||||
ctr.LockedTTL = ptr.Ref(0 * time.Hour.Milliseconds())
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
@@ -674,12 +678,14 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
|
||||
FailureTTLMillis: failureTTL.Milliseconds(),
|
||||
InactivityTTLMillis: inactivityTTL.Milliseconds(),
|
||||
LockedTTLMillis: lockedTTL.Milliseconds(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.EqualValues(t, 2, atomic.LoadInt64(&setCalled))
|
||||
require.Equal(t, failureTTL.Milliseconds(), got.FailureTTLMillis)
|
||||
require.Equal(t, inactivityTTL.Milliseconds(), got.InactivityTTLMillis)
|
||||
require.Equal(t, lockedTTL.Milliseconds(), got.LockedTTLMillis)
|
||||
})
|
||||
|
||||
t.Run("IgnoredUnlicensed", func(t *testing.T) {
|
||||
@@ -691,6 +697,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
|
||||
ctr.FailureTTLMillis = ptr.Ref(0 * time.Hour.Milliseconds())
|
||||
ctr.InactivityTTLMillis = ptr.Ref(0 * time.Hour.Milliseconds())
|
||||
ctr.LockedTTL = ptr.Ref(0 * time.Hour.Milliseconds())
|
||||
})
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
@@ -706,10 +713,12 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
|
||||
FailureTTLMillis: failureTTL.Milliseconds(),
|
||||
InactivityTTLMillis: inactivityTTL.Milliseconds(),
|
||||
LockedTTLMillis: lockedTTL.Milliseconds(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, got.FailureTTLMillis)
|
||||
require.Zero(t, got.InactivityTTLMillis)
|
||||
require.Zero(t, got.LockedTTLMillis)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -106,8 +106,11 @@ type CreateTemplateRequest struct {
|
||||
// stops all resources for failed workspaces created from this template.
|
||||
FailureTTLMillis *int64 `json:"failure_ttl_ms,omitempty"`
|
||||
// InactivityTTLMillis allows optionally specifying the max lifetime before Coder
|
||||
// deletes inactive workspaces created from this template.
|
||||
// locks inactive workspaces created from this template.
|
||||
InactivityTTLMillis *int64 `json:"inactivity_ttl_ms,omitempty"`
|
||||
// LockedTTL allows optionally specifying the max lifetime before Coder
|
||||
// permanently deletes locked workspaces created from this template.
|
||||
LockedTTL *int64 `json:"locked_ttl_ms,omitempty"`
|
||||
|
||||
// DisableEveryoneGroupAccess allows optionally disabling the default
|
||||
// behavior of granting the 'everyone' group access to use the template.
|
||||
|
||||
@@ -41,11 +41,12 @@ type Template struct {
|
||||
AllowUserAutostop bool `json:"allow_user_autostop"`
|
||||
AllowUserCancelWorkspaceJobs bool `json:"allow_user_cancel_workspace_jobs"`
|
||||
|
||||
// FailureTTLMillis and InactivityTTLMillis are enterprise-only. Their
|
||||
// FailureTTLMillis, InactivityTTLMillis, and LockedTTLMillis are enterprise-only. Their
|
||||
// values are used if your license is entitled to use the advanced
|
||||
// template scheduling feature.
|
||||
FailureTTLMillis int64 `json:"failure_ttl_ms"`
|
||||
InactivityTTLMillis int64 `json:"inactivity_ttl_ms"`
|
||||
LockedTTLMillis int64 `json:"locked_ttl_ms"`
|
||||
}
|
||||
|
||||
type TransitionStats struct {
|
||||
@@ -103,6 +104,7 @@ type UpdateTemplateMeta struct {
|
||||
AllowUserCancelWorkspaceJobs bool `json:"allow_user_cancel_workspace_jobs,omitempty"`
|
||||
FailureTTLMillis int64 `json:"failure_ttl_ms,omitempty"`
|
||||
InactivityTTLMillis int64 `json:"inactivity_ttl_ms,omitempty"`
|
||||
LockedTTLMillis int64 `json:"locked_ttl_ms,omitempty"`
|
||||
}
|
||||
|
||||
type TemplateExample struct {
|
||||
|
||||
+12
-12
@@ -9,18 +9,18 @@ We track the following resources:
|
||||
|
||||
<!-- Code generated by 'make docs/admin/audit-logs.md'. DO NOT EDIT -->
|
||||
|
||||
| <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> |
|
||||
| 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>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></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> |
|
||||
| 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>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</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>inactivity_ttl</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>updated_at</td><td>false</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>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>git_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>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>false</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</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>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>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_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>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>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>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||
| <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> |
|
||||
| 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>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></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> |
|
||||
| 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>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</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>inactivity_ttl</td><td>true</td></tr><tr><td>locked_ttl</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>updated_at</td><td>false</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>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>git_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>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>false</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</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>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>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_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>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>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>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||
|
||||
<!-- End generated by 'make docs/admin/audit-logs.md'. -->
|
||||
|
||||
|
||||
+28
-24
@@ -1351,6 +1351,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"failure_ttl_ms": 0,
|
||||
"icon": "string",
|
||||
"inactivity_ttl_ms": 0,
|
||||
"locked_ttl_ms": 0,
|
||||
"max_ttl_ms": 0,
|
||||
"name": "string",
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1"
|
||||
@@ -1370,7 +1371,8 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
| `display_name` | string | false | | Display name is the displayed name of the template. |
|
||||
| `failure_ttl_ms` | integer | false | | Failure ttl ms allows optionally specifying the max lifetime before Coder stops all resources for failed workspaces created from this template. |
|
||||
| `icon` | string | false | | Icon is a relative path or external URL that specifies an icon to be displayed in the dashboard. |
|
||||
| `inactivity_ttl_ms` | integer | false | | Inactivity ttl ms allows optionally specifying the max lifetime before Coder deletes inactive workspaces created from this template. |
|
||||
| `inactivity_ttl_ms` | integer | false | | Inactivity ttl ms allows optionally specifying the max lifetime before Coder locks inactive workspaces created from this template. |
|
||||
| `locked_ttl_ms` | integer | false | | Locked ttl ms allows optionally specifying the max lifetime before Coder permanently deletes locked workspaces created from this template. |
|
||||
| `max_ttl_ms` | integer | false | | Max ttl ms allows optionally specifying the max lifetime for workspaces created from this template. |
|
||||
| `name` | string | true | | Name is the name of the template. |
|
||||
| `template_version_id` | string | true | | Template version ID is an in-progress or completed job to use as an initial version of the template. |
|
||||
@@ -3733,6 +3735,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"inactivity_ttl_ms": 0,
|
||||
"locked_ttl_ms": 0,
|
||||
"max_ttl_ms": 0,
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
@@ -3743,29 +3746,30 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ---------------------------------- | ------------------------------------------------------------------ | -------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||
| `active_version_id` | string | 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_autostop` | boolean | false | | |
|
||||
| `allow_user_cancel_workspace_jobs` | boolean | false | | |
|
||||
| `build_time_stats` | [codersdk.TemplateBuildTimeStats](#codersdktemplatebuildtimestats) | false | | |
|
||||
| `created_at` | string | false | | |
|
||||
| `created_by_id` | string | false | | |
|
||||
| `created_by_name` | string | false | | |
|
||||
| `default_ttl_ms` | integer | false | | |
|
||||
| `description` | string | false | | |
|
||||
| `display_name` | string | false | | |
|
||||
| `failure_ttl_ms` | integer | false | | Failure ttl ms and InactivityTTLMillis are enterprise-only. Their values are used if your license is entitled to use the advanced template scheduling feature. |
|
||||
| `icon` | string | false | | |
|
||||
| `id` | string | false | | |
|
||||
| `inactivity_ttl_ms` | integer | false | | |
|
||||
| `max_ttl_ms` | integer | false | | Max ttl ms is an enterprise feature. It's value is only used if your license is entitled to use the advanced template scheduling feature. |
|
||||
| `name` | string | false | | |
|
||||
| `organization_id` | string | false | | |
|
||||
| `provisioner` | string | false | | |
|
||||
| `updated_at` | string | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ---------------------------------- | ------------------------------------------------------------------ | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||
| `active_version_id` | string | 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_autostop` | boolean | false | | |
|
||||
| `allow_user_cancel_workspace_jobs` | boolean | false | | |
|
||||
| `build_time_stats` | [codersdk.TemplateBuildTimeStats](#codersdktemplatebuildtimestats) | false | | |
|
||||
| `created_at` | string | false | | |
|
||||
| `created_by_id` | string | false | | |
|
||||
| `created_by_name` | string | false | | |
|
||||
| `default_ttl_ms` | integer | false | | |
|
||||
| `description` | string | false | | |
|
||||
| `display_name` | string | false | | |
|
||||
| `failure_ttl_ms` | integer | false | | Failure ttl ms InactivityTTLMillis, and LockedTTLMillis are enterprise-only. Their values are used if your license is entitled to use the advanced template scheduling feature. |
|
||||
| `icon` | string | false | | |
|
||||
| `id` | string | false | | |
|
||||
| `inactivity_ttl_ms` | integer | false | | |
|
||||
| `locked_ttl_ms` | integer | false | | |
|
||||
| `max_ttl_ms` | integer | false | | Max ttl ms is an enterprise feature. It's value is only used if your license is entitled to use the advanced template scheduling feature. |
|
||||
| `name` | string | false | | |
|
||||
| `organization_id` | string | false | | |
|
||||
| `provisioner` | string | false | | |
|
||||
| `updated_at` | string | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
|
||||
+34
-27
@@ -51,6 +51,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"inactivity_ttl_ms": 0,
|
||||
"locked_ttl_ms": 0,
|
||||
"max_ttl_ms": 0,
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
@@ -70,33 +71,34 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------------------------------------ | ---------------------------------------------------------------------------- | -------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `[array item]` | array | false | | |
|
||||
| `» active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||
| `» active_version_id` | string(uuid) | 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_autostop` | boolean | false | | |
|
||||
| `» allow_user_cancel_workspace_jobs` | boolean | false | | |
|
||||
| `» build_time_stats` | [codersdk.TemplateBuildTimeStats](schemas.md#codersdktemplatebuildtimestats) | false | | |
|
||||
| `»» [any property]` | [codersdk.TransitionStats](schemas.md#codersdktransitionstats) | false | | |
|
||||
| `»»» p50` | integer | false | | |
|
||||
| `»»» p95` | integer | false | | |
|
||||
| `» created_at` | string(date-time) | false | | |
|
||||
| `» created_by_id` | string(uuid) | false | | |
|
||||
| `» created_by_name` | string | false | | |
|
||||
| `» default_ttl_ms` | integer | false | | |
|
||||
| `» description` | string | false | | |
|
||||
| `» display_name` | string | false | | |
|
||||
| `» failure_ttl_ms` | integer | false | | Failure ttl ms and InactivityTTLMillis are enterprise-only. Their values are used if your license is entitled to use the advanced template scheduling feature. |
|
||||
| `» icon` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» inactivity_ttl_ms` | integer | false | | |
|
||||
| `» max_ttl_ms` | integer | false | | Max ttl ms is an enterprise feature. It's value is only used if your license is entitled to use the advanced template scheduling feature. |
|
||||
| `» name` | string | false | | |
|
||||
| `» organization_id` | string(uuid) | false | | |
|
||||
| `» provisioner` | string | false | | |
|
||||
| `» updated_at` | string(date-time) | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
| ------------------------------------ | ---------------------------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `[array item]` | array | false | | |
|
||||
| `» active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||
| `» active_version_id` | string(uuid) | 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_autostop` | boolean | false | | |
|
||||
| `» allow_user_cancel_workspace_jobs` | boolean | false | | |
|
||||
| `» build_time_stats` | [codersdk.TemplateBuildTimeStats](schemas.md#codersdktemplatebuildtimestats) | false | | |
|
||||
| `»» [any property]` | [codersdk.TransitionStats](schemas.md#codersdktransitionstats) | false | | |
|
||||
| `»»» p50` | integer | false | | |
|
||||
| `»»» p95` | integer | false | | |
|
||||
| `» created_at` | string(date-time) | false | | |
|
||||
| `» created_by_id` | string(uuid) | false | | |
|
||||
| `» created_by_name` | string | false | | |
|
||||
| `» default_ttl_ms` | integer | false | | |
|
||||
| `» description` | string | false | | |
|
||||
| `» display_name` | string | false | | |
|
||||
| `» failure_ttl_ms` | integer | false | | Failure ttl ms InactivityTTLMillis, and LockedTTLMillis are enterprise-only. Their values are used if your license is entitled to use the advanced template scheduling feature. |
|
||||
| `» icon` | string | false | | |
|
||||
| `» id` | string(uuid) | false | | |
|
||||
| `» inactivity_ttl_ms` | integer | false | | |
|
||||
| `» locked_ttl_ms` | integer | false | | |
|
||||
| `» max_ttl_ms` | integer | false | | Max ttl ms is an enterprise feature. It's value is only used if your license is entitled to use the advanced template scheduling feature. |
|
||||
| `» name` | string | false | | |
|
||||
| `» organization_id` | string(uuid) | false | | |
|
||||
| `» provisioner` | string | false | | |
|
||||
| `» updated_at` | string(date-time) | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
@@ -134,6 +136,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
||||
"failure_ttl_ms": 0,
|
||||
"icon": "string",
|
||||
"inactivity_ttl_ms": 0,
|
||||
"locked_ttl_ms": 0,
|
||||
"max_ttl_ms": 0,
|
||||
"name": "string",
|
||||
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1"
|
||||
@@ -178,6 +181,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"inactivity_ttl_ms": 0,
|
||||
"locked_ttl_ms": 0,
|
||||
"max_ttl_ms": 0,
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
@@ -305,6 +309,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"inactivity_ttl_ms": 0,
|
||||
"locked_ttl_ms": 0,
|
||||
"max_ttl_ms": 0,
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
@@ -628,6 +633,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template} \
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"inactivity_ttl_ms": 0,
|
||||
"locked_ttl_ms": 0,
|
||||
"max_ttl_ms": 0,
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
@@ -738,6 +744,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \
|
||||
"icon": "string",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"inactivity_ttl_ms": 0,
|
||||
"locked_ttl_ms": 0,
|
||||
"max_ttl_ms": 0,
|
||||
"name": "string",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
|
||||
@@ -77,6 +77,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
||||
"max_ttl": ActionTrack,
|
||||
"failure_ttl": ActionTrack,
|
||||
"inactivity_ttl": ActionTrack,
|
||||
"locked_ttl": ActionTrack,
|
||||
},
|
||||
&database.TemplateVersion{}: {
|
||||
"id": ActionTrack,
|
||||
|
||||
@@ -327,6 +327,7 @@ func (*enterpriseTemplateScheduleStore) GetTemplateScheduleOptions(ctx context.C
|
||||
MaxTTL: time.Duration(tpl.MaxTTL),
|
||||
FailureTTL: time.Duration(tpl.FailureTTL),
|
||||
InactivityTTL: time.Duration(tpl.InactivityTTL),
|
||||
LockedTTL: time.Duration(tpl.LockedTTL),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -335,6 +336,7 @@ func (*enterpriseTemplateScheduleStore) SetTemplateScheduleOptions(ctx context.C
|
||||
int64(opts.MaxTTL) == tpl.MaxTTL &&
|
||||
int64(opts.FailureTTL) == tpl.FailureTTL &&
|
||||
int64(opts.InactivityTTL) == tpl.InactivityTTL &&
|
||||
int64(opts.LockedTTL) == tpl.LockedTTL &&
|
||||
opts.UserAutostartEnabled == tpl.AllowUserAutostart &&
|
||||
opts.UserAutostopEnabled == tpl.AllowUserAutostop {
|
||||
// Avoid updating the UpdatedAt timestamp if nothing will be changed.
|
||||
@@ -350,6 +352,7 @@ func (*enterpriseTemplateScheduleStore) SetTemplateScheduleOptions(ctx context.C
|
||||
MaxTTL: int64(opts.MaxTTL),
|
||||
FailureTTL: int64(opts.FailureTTL),
|
||||
InactivityTTL: int64(opts.InactivityTTL),
|
||||
LockedTTL: int64(opts.LockedTTL),
|
||||
})
|
||||
if err != nil {
|
||||
return database.Template{}, xerrors.Errorf("update template schedule: %w", err)
|
||||
|
||||
@@ -179,6 +179,7 @@ export interface CreateTemplateRequest {
|
||||
readonly allow_user_autostop?: boolean
|
||||
readonly failure_ttl_ms?: number
|
||||
readonly inactivity_ttl_ms?: number
|
||||
readonly locked_ttl_ms?: number
|
||||
readonly disable_everyone_group_access: boolean
|
||||
}
|
||||
|
||||
@@ -805,6 +806,7 @@ export interface Template {
|
||||
readonly allow_user_cancel_workspace_jobs: boolean
|
||||
readonly failure_ttl_ms: number
|
||||
readonly inactivity_ttl_ms: number
|
||||
readonly locked_ttl_ms: number
|
||||
}
|
||||
|
||||
// From codersdk/templates.go
|
||||
@@ -972,6 +974,7 @@ export interface UpdateTemplateMeta {
|
||||
readonly allow_user_cancel_workspace_jobs?: boolean
|
||||
readonly failure_ttl_ms?: number
|
||||
readonly inactivity_ttl_ms?: number
|
||||
readonly locked_ttl_ms?: number
|
||||
}
|
||||
|
||||
// From codersdk/users.go
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
"inactivityTTLHelperText_zero": "Coder will not automatically delete inactive workspaces",
|
||||
"inactivityTTLHelperText_one": "Coder will automatically delete inactive workspaces after {{count}} day.",
|
||||
"inactivityTTLHelperText_other": "Coder will automatically delete inactive workspaces after {{count}} days.",
|
||||
"lockedTTLHelperText_zero": "Coder will not automatically delete locked workspaces",
|
||||
"lockedTTLHelperText_one": "Coder will automatically delete locked workspaces after {{count}} day.",
|
||||
"lockedTTLHelperText_other": "Coder will automatically delete locked workspaces after {{count}} days.",
|
||||
"allowUserCancelWorkspaceJobsLabel": "Allow users to cancel in-progress workspace jobs.",
|
||||
"allowUserCancelWorkspaceJobsNotice": "Depending on your template, canceling builds may leave workspaces in an unhealthy state. This option isn't recommended for most use cases.",
|
||||
"allowUsersCancelHelperText": "If checked, users may be able to corrupt their workspace.",
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ const validFormValues: FormValues = {
|
||||
allow_user_autostop: false,
|
||||
failure_ttl_ms: 0,
|
||||
inactivity_ttl_ms: 0,
|
||||
locked_ttl_ms: 0,
|
||||
}
|
||||
|
||||
const renderTemplateSettingsPage = async () => {
|
||||
|
||||
+61
-1
@@ -25,6 +25,7 @@ const MS_HOUR_CONVERSION = 3600000
|
||||
const MS_DAY_CONVERSION = 86400000
|
||||
const FAILURE_CLEANUP_DEFAULT = 7
|
||||
const INACTIVITY_CLEANUP_DEFAULT = 180
|
||||
const LOCKED_CLEANUP_DEFAULT = 30
|
||||
|
||||
export interface TemplateScheduleForm {
|
||||
template: Template
|
||||
@@ -65,6 +66,9 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||
inactivity_ttl_ms: allowAdvancedScheduling
|
||||
? template.inactivity_ttl_ms / MS_DAY_CONVERSION
|
||||
: 0,
|
||||
locked_ttl_ms: allowAdvancedScheduling
|
||||
? template.locked_ttl_ms / MS_DAY_CONVERSION
|
||||
: 0,
|
||||
|
||||
allow_user_autostart: template.allow_user_autostart,
|
||||
allow_user_autostop: template.allow_user_autostop,
|
||||
@@ -72,6 +76,8 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||
allowAdvancedScheduling && Boolean(template.failure_ttl_ms),
|
||||
inactivity_cleanup_enabled:
|
||||
allowAdvancedScheduling && Boolean(template.inactivity_ttl_ms),
|
||||
locked_cleanup_enabled:
|
||||
allowAdvancedScheduling && Boolean(template.locked_ttl_ms),
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: () => {
|
||||
@@ -114,6 +120,9 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||
inactivity_ttl_ms: form.values.inactivity_ttl_ms
|
||||
? form.values.inactivity_ttl_ms * MS_DAY_CONVERSION
|
||||
: undefined,
|
||||
locked_ttl_ms: form.values.locked_ttl_ms
|
||||
? form.values.locked_ttl_ms * MS_DAY_CONVERSION
|
||||
: undefined,
|
||||
|
||||
allow_user_autostart: form.values.allow_user_autostart,
|
||||
allow_user_autostop: form.values.allow_user_autostop,
|
||||
@@ -158,6 +167,25 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||
}
|
||||
}
|
||||
|
||||
const handleToggleLockedCleanup = async (e: ChangeEvent) => {
|
||||
form.handleChange(e)
|
||||
if (!form.values.locked_cleanup_enabled) {
|
||||
// fill failure_ttl_ms with defaults
|
||||
await form.setValues({
|
||||
...form.values,
|
||||
locked_cleanup_enabled: true,
|
||||
locked_ttl_ms: LOCKED_CLEANUP_DEFAULT,
|
||||
})
|
||||
} else {
|
||||
// clear failure_ttl_ms
|
||||
await form.setValues({
|
||||
...form.values,
|
||||
locked_cleanup_enabled: false,
|
||||
locked_ttl_ms: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<HorizontalForm
|
||||
onSubmit={form.handleSubmit}
|
||||
@@ -298,7 +326,7 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||
</FormSection>
|
||||
<FormSection
|
||||
title="Inactivity Cleanup"
|
||||
description="When enabled, Coder will automatically delete workspaces that are in an inactive state after a specified number of days."
|
||||
description="When enabled, Coder will lock workspaces that have not been accessed after a specified number of days."
|
||||
>
|
||||
<FormFields>
|
||||
<FormControlLabel
|
||||
@@ -330,6 +358,38 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
|
||||
/>
|
||||
</FormFields>
|
||||
</FormSection>
|
||||
<FormSection
|
||||
title="Locked Cleanup"
|
||||
description="When enabled, Coder will permanently delete workspaces that have been locked for a specified number of days."
|
||||
>
|
||||
<FormFields>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
name="lockedCleanupEnabled"
|
||||
checked={form.values.locked_cleanup_enabled}
|
||||
onChange={handleToggleLockedCleanup}
|
||||
/>
|
||||
}
|
||||
label="Enable Locked Cleanup"
|
||||
/>
|
||||
<TextField
|
||||
{...getFieldHelpers(
|
||||
"locked_ttl_ms",
|
||||
<TTLHelperText
|
||||
translationName="lockedTTLHelperText"
|
||||
ttl={form.values.locked_ttl_ms}
|
||||
/>,
|
||||
)}
|
||||
disabled={isSubmitting || !form.values.locked_cleanup_enabled}
|
||||
fullWidth
|
||||
inputProps={{ min: 0, step: "any" }}
|
||||
label="Time until cleanup (days)"
|
||||
type="number"
|
||||
aria-label="Locked Cleanup"
|
||||
/>
|
||||
</FormFields>
|
||||
</FormSection>
|
||||
</>
|
||||
)}
|
||||
<InactivityDialog
|
||||
|
||||
+15
@@ -5,6 +5,7 @@ import i18next from "i18next"
|
||||
export interface TemplateScheduleFormValues extends UpdateTemplateMeta {
|
||||
failure_cleanup_enabled: boolean
|
||||
inactivity_cleanup_enabled: boolean
|
||||
locked_cleanup_enabled: boolean
|
||||
}
|
||||
|
||||
const MAX_TTL_DAYS = 7
|
||||
@@ -63,6 +64,20 @@ export const getValidationSchema = (): Yup.AnyObjectSchema =>
|
||||
}
|
||||
},
|
||||
),
|
||||
locked_ttl_ms: Yup.number()
|
||||
.min(0, "Locked cleanup days must not be less than 0.")
|
||||
.test(
|
||||
"positive-if-enabled",
|
||||
"Locked cleanup days must be greater than zero when enabled.",
|
||||
function (value) {
|
||||
const parent = this.parent as TemplateScheduleFormValues
|
||||
if (parent.locked_cleanup_enabled) {
|
||||
return Boolean(value)
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
),
|
||||
allow_user_autostart: Yup.boolean(),
|
||||
allow_user_autostop: Yup.boolean(),
|
||||
})
|
||||
|
||||
+39
-1
@@ -22,6 +22,7 @@ const validFormValues = {
|
||||
max_ttl_ms: 2,
|
||||
failure_ttl_ms: 7,
|
||||
inactivity_ttl_ms: 180,
|
||||
locked_ttl_ms: 30,
|
||||
}
|
||||
|
||||
const renderTemplateSchedulePage = async () => {
|
||||
@@ -37,11 +38,13 @@ const fillAndSubmitForm = async ({
|
||||
max_ttl_ms,
|
||||
failure_ttl_ms,
|
||||
inactivity_ttl_ms,
|
||||
locked_ttl_ms,
|
||||
}: {
|
||||
default_ttl_ms: number
|
||||
max_ttl_ms: number
|
||||
failure_ttl_ms: number
|
||||
inactivity_ttl_ms: number
|
||||
locked_ttl_ms: number
|
||||
}) => {
|
||||
const user = userEvent.setup()
|
||||
const defaultTtlLabel = t("defaultTtlLabel", { ns: "templateSettingsPage" })
|
||||
@@ -64,6 +67,11 @@ const fillAndSubmitForm = async ({
|
||||
})
|
||||
await user.type(inactivityTtlField, inactivity_ttl_ms.toString())
|
||||
|
||||
const lockedTtlField = screen.getByRole("checkbox", {
|
||||
name: /Locked Cleanup/i,
|
||||
})
|
||||
await user.type(lockedTtlField, locked_ttl_ms.toString())
|
||||
|
||||
const submitButton = await screen.findByText(
|
||||
FooterFormLanguage.defaultSubmitLabel,
|
||||
)
|
||||
@@ -111,7 +119,7 @@ describe("TemplateSchedulePage", () => {
|
||||
)
|
||||
})
|
||||
|
||||
test("failure and inactivity ttl converted to and from days", async () => {
|
||||
test("failure, inactivity, and locked ttl converted to and from days", async () => {
|
||||
await renderTemplateSchedulePage()
|
||||
|
||||
jest.spyOn(API, "updateTemplateMeta").mockResolvedValueOnce({
|
||||
@@ -127,6 +135,7 @@ describe("TemplateSchedulePage", () => {
|
||||
expect.objectContaining({
|
||||
failure_ttl_ms: validFormValues.failure_ttl_ms * 86400000,
|
||||
inactivity_ttl_ms: validFormValues.inactivity_ttl_ms * 86400000,
|
||||
locked_ttl_ms: validFormValues.locked_ttl_ms * 86400000,
|
||||
}),
|
||||
),
|
||||
)
|
||||
@@ -218,4 +227,33 @@ describe("TemplateSchedulePage", () => {
|
||||
"Inactivity cleanup days must not be less than 0.",
|
||||
)
|
||||
})
|
||||
|
||||
it("allows a locked ttl of 7 days", () => {
|
||||
const values: UpdateTemplateMeta = {
|
||||
...validFormValues,
|
||||
locked_ttl_ms: 86400000 * 7,
|
||||
}
|
||||
const validate = () => getValidationSchema().validateSync(values)
|
||||
expect(validate).not.toThrowError()
|
||||
})
|
||||
|
||||
it("allows a locked ttl of 0", () => {
|
||||
const values: UpdateTemplateMeta = {
|
||||
...validFormValues,
|
||||
locked_ttl_ms: 0,
|
||||
}
|
||||
const validate = () => getValidationSchema().validateSync(values)
|
||||
expect(validate).not.toThrowError()
|
||||
})
|
||||
|
||||
it("disallows a negative inactivity ttl", () => {
|
||||
const values: UpdateTemplateMeta = {
|
||||
...validFormValues,
|
||||
locked_ttl_ms: -1,
|
||||
}
|
||||
const validate = () => getValidationSchema().validateSync(values)
|
||||
expect(validate).toThrowError(
|
||||
"Locked cleanup days must not be less than 0.",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -388,6 +388,7 @@ export const MockTemplate: TypesGen.Template = {
|
||||
allow_user_cancel_workspace_jobs: true,
|
||||
failure_ttl_ms: 0,
|
||||
inactivity_ttl_ms: 0,
|
||||
locked_ttl_ms: 0,
|
||||
allow_user_autostart: false,
|
||||
allow_user_autostop: false,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user