chore: rename template restart requirement to autostop requirement (#9295)

This commit is contained in:
Dean Sheather 2023-08-29 11:35:05 -07:00 committed by GitHub
parent fc4683d8b3
commit a572800d47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 925 additions and 891 deletions

View File

@ -316,8 +316,8 @@ func TestScheduleOverride(t *testing.T) {
stdoutBuf = &bytes.Buffer{}
)
require.Zero(t, template.DefaultTTLMillis)
require.Empty(t, template.RestartRequirement.DaysOfWeek)
require.Zero(t, template.RestartRequirement.Weeks)
require.Empty(t, template.AutostopRequirement.DaysOfWeek)
require.Zero(t, template.AutostopRequirement.Weeks)
// Unset the workspace TTL
err = client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{TTLMillis: nil})

View File

@ -15,19 +15,19 @@ import (
func (r *RootCmd) templateEdit() *clibase.Cmd {
var (
name string
displayName string
description string
icon string
defaultTTL time.Duration
maxTTL time.Duration
restartRequirementDaysOfWeek []string
restartRequirementWeeks int64
failureTTL time.Duration
inactivityTTL time.Duration
allowUserCancelWorkspaceJobs bool
allowUserAutostart bool
allowUserAutostop bool
name string
displayName string
description string
icon string
defaultTTL time.Duration
maxTTL time.Duration
autostopRequirementDaysOfWeek []string
autostopRequirementWeeks int64
failureTTL time.Duration
inactivityTTL time.Duration
allowUserCancelWorkspaceJobs bool
allowUserAutostart bool
allowUserAutostop bool
)
client := new(codersdk.Client)
@ -51,9 +51,9 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
}
}
unsetRestartRequirementDaysOfWeek := len(restartRequirementDaysOfWeek) == 1 && restartRequirementDaysOfWeek[0] == "none"
requiresEntitlement := (len(restartRequirementDaysOfWeek) > 0 && !unsetRestartRequirementDaysOfWeek) ||
restartRequirementWeeks > 0 ||
unsetAutostopRequirementDaysOfWeek := len(autostopRequirementDaysOfWeek) == 1 && autostopRequirementDaysOfWeek[0] == "none"
requiresEntitlement := (len(autostopRequirementDaysOfWeek) > 0 && !unsetAutostopRequirementDaysOfWeek) ||
autostopRequirementWeeks > 0 ||
!allowUserAutostart ||
!allowUserAutostop ||
maxTTL != 0 ||
@ -84,11 +84,11 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
// Copy the default value if the list is empty, or if the user
// specified the "none" value clear the list.
if len(restartRequirementDaysOfWeek) == 0 {
restartRequirementDaysOfWeek = template.RestartRequirement.DaysOfWeek
if len(autostopRequirementDaysOfWeek) == 0 {
autostopRequirementDaysOfWeek = template.AutostopRequirement.DaysOfWeek
}
if unsetRestartRequirementDaysOfWeek {
restartRequirementDaysOfWeek = []string{}
if unsetAutostopRequirementDaysOfWeek {
autostopRequirementDaysOfWeek = []string{}
}
// NOTE: coderd will ignore empty fields.
@ -99,9 +99,9 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
Icon: icon,
DefaultTTLMillis: defaultTTL.Milliseconds(),
MaxTTLMillis: maxTTL.Milliseconds(),
RestartRequirement: &codersdk.TemplateRestartRequirement{
DaysOfWeek: restartRequirementDaysOfWeek,
Weeks: restartRequirementWeeks,
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
DaysOfWeek: autostopRequirementDaysOfWeek,
Weeks: autostopRequirementWeeks,
},
FailureTTLMillis: failureTTL.Milliseconds(),
TimeTilDormantMillis: inactivityTTL.Milliseconds(),
@ -151,28 +151,28 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
Value: clibase.DurationOf(&maxTTL),
},
{
Flag: "restart-requirement-weekdays",
Description: "Edit the template restart requirement weekdays - workspaces created from this template must be restarted on the given weekdays. To unset this value for the template (and disable the restart requirement for the template), pass 'none'.",
Flag: "autostop-requirement-weekdays",
Description: "Edit the template autostop requirement weekdays - workspaces created from this template must be restarted on the given weekdays. To unset this value for the template (and disable the autostop requirement for the template), pass 'none'.",
// TODO(@dean): unhide when we delete max_ttl
Hidden: true,
Value: clibase.Validate(clibase.StringArrayOf(&restartRequirementDaysOfWeek), func(value *clibase.StringArray) error {
Value: clibase.Validate(clibase.StringArrayOf(&autostopRequirementDaysOfWeek), func(value *clibase.StringArray) error {
v := value.GetSlice()
if len(v) == 1 && v[0] == "none" {
return nil
}
_, err := codersdk.WeekdaysToBitmap(v)
if err != nil {
return xerrors.Errorf("invalid restart requirement days of week %q: %w", strings.Join(v, ","), err)
return xerrors.Errorf("invalid autostop requirement days of week %q: %w", strings.Join(v, ","), err)
}
return nil
}),
},
{
Flag: "restart-requirement-weeks",
Description: "Edit the template restart requirement weeks - workspaces created from this template must be restarted on an n-weekly basis.",
Flag: "autostop-requirement-weeks",
Description: "Edit the template autostop requirement weeks - workspaces created from this template must be restarted on an n-weekly basis.",
// TODO(@dean): unhide when we delete max_ttl
Hidden: true,
Value: clibase.Int64Of(&restartRequirementWeeks),
Value: clibase.Int64Of(&autostopRequirementWeeks),
},
{
Flag: "failure-ttl",

View File

@ -242,7 +242,7 @@ func TestTemplateEdit(t *testing.T) {
assert.Equal(t, "", updated.Icon)
assert.Equal(t, "", updated.DisplayName)
})
t.Run("RestartRequirement", func(t *testing.T) {
t.Run("AutostopRequirement", func(t *testing.T) {
t.Parallel()
t.Run("BlockedAGPL", func(t *testing.T) {
t.Parallel()
@ -252,7 +252,7 @@ func TestTemplateEdit(t *testing.T) {
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
ctr.DefaultTTLMillis = nil
ctr.RestartRequirement = nil
ctr.AutostopRequirement = nil
})
cases := []struct {
@ -263,20 +263,20 @@ func TestTemplateEdit(t *testing.T) {
{
name: "Weekdays",
flags: []string{
"--restart-requirement-weekdays", "monday",
"--autostop-requirement-weekdays", "monday",
},
},
{
name: "WeekdaysNoneAllowed",
flags: []string{
"--restart-requirement-weekdays", "none",
"--autostop-requirement-weekdays", "none",
},
ok: true,
},
{
name: "Weeks",
flags: []string{
"--restart-requirement-weeks", "1",
"--autostop-requirement-weeks", "1",
},
},
}
@ -312,8 +312,8 @@ func TestTemplateEdit(t *testing.T) {
assert.Equal(t, template.Icon, updated.Icon)
assert.Equal(t, template.DisplayName, updated.DisplayName)
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
assert.Equal(t, template.RestartRequirement.DaysOfWeek, updated.RestartRequirement.DaysOfWeek)
assert.Equal(t, template.RestartRequirement.Weeks, updated.RestartRequirement.Weeks)
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
})
}
})
@ -326,7 +326,7 @@ func TestTemplateEdit(t *testing.T) {
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
ctr.DefaultTTLMillis = nil
ctr.RestartRequirement = nil
ctr.AutostopRequirement = nil
})
// Make a proxy server that will return a valid entitlements
@ -377,20 +377,20 @@ func TestTemplateEdit(t *testing.T) {
{
name: "Weekdays",
flags: []string{
"--restart-requirement-weekdays", "monday",
"--autostop-requirement-weekdays", "monday",
},
},
{
name: "WeekdaysNoneAllowed",
flags: []string{
"--restart-requirement-weekdays", "none",
"--autostop-requirement-weekdays", "none",
},
ok: true,
},
{
name: "Weeks",
flags: []string{
"--restart-requirement-weeks", "1",
"--autostop-requirement-weeks", "1",
},
},
}
@ -426,8 +426,8 @@ func TestTemplateEdit(t *testing.T) {
assert.Equal(t, template.Icon, updated.Icon)
assert.Equal(t, template.DisplayName, updated.DisplayName)
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
assert.Equal(t, template.RestartRequirement.DaysOfWeek, updated.RestartRequirement.DaysOfWeek)
assert.Equal(t, template.RestartRequirement.Weeks, updated.RestartRequirement.Weeks)
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
})
}
})
@ -439,7 +439,7 @@ func TestTemplateEdit(t *testing.T) {
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
ctr.DefaultTTLMillis = nil
ctr.RestartRequirement = nil
ctr.AutostopRequirement = nil
})
// Make a proxy server that will return a valid entitlements
@ -475,8 +475,8 @@ func TestTemplateEdit(t *testing.T) {
var req codersdk.UpdateTemplateMeta
err = json.Unmarshal(body, &req)
require.NoError(t, err)
assert.Equal(t, req.RestartRequirement.DaysOfWeek, []string{"monday", "tuesday"})
assert.EqualValues(t, req.RestartRequirement.Weeks, 3)
assert.Equal(t, req.AutostopRequirement.DaysOfWeek, []string{"monday", "tuesday"})
assert.EqualValues(t, req.AutostopRequirement.Weeks, 3)
r.Body = io.NopCloser(bytes.NewReader(body))
atomic.AddInt64(&updateTemplateCalled, 1)
@ -504,8 +504,8 @@ func TestTemplateEdit(t *testing.T) {
"templates",
"edit",
template.Name,
"--restart-requirement-weekdays", "monday,tuesday",
"--restart-requirement-weeks", "3",
"--autostop-requirement-weekdays", "monday,tuesday",
"--autostop-requirement-weeks", "3",
}
inv, root := clitest.New(t, cmdArgs...)
clitest.SetupConfig(t, proxyClient, root)
@ -525,8 +525,8 @@ func TestTemplateEdit(t *testing.T) {
assert.Equal(t, template.Icon, updated.Icon)
assert.Equal(t, template.DisplayName, updated.DisplayName)
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
assert.Equal(t, template.RestartRequirement.DaysOfWeek, updated.RestartRequirement.DaysOfWeek)
assert.Equal(t, template.RestartRequirement.Weeks, updated.RestartRequirement.Weeks)
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
})
})
// TODO(@dean): remove this test when we remove max_ttl
@ -750,7 +750,7 @@ func TestTemplateEdit(t *testing.T) {
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
ctr.DefaultTTLMillis = nil
ctr.RestartRequirement = nil
ctr.AutostopRequirement = nil
ctr.FailureTTLMillis = nil
ctr.TimeTilDormantMillis = nil
})
@ -793,8 +793,8 @@ func TestTemplateEdit(t *testing.T) {
assert.Equal(t, template.Icon, updated.Icon)
assert.Equal(t, template.DisplayName, updated.DisplayName)
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
assert.Equal(t, template.RestartRequirement.DaysOfWeek, updated.RestartRequirement.DaysOfWeek)
assert.Equal(t, template.RestartRequirement.Weeks, updated.RestartRequirement.Weeks)
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
assert.Equal(t, template.FailureTTLMillis, updated.FailureTTLMillis)
@ -887,8 +887,8 @@ func TestTemplateEdit(t *testing.T) {
assert.Equal(t, template.Icon, updated.Icon)
assert.Equal(t, template.DisplayName, updated.DisplayName)
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
assert.Equal(t, template.RestartRequirement.DaysOfWeek, updated.RestartRequirement.DaysOfWeek)
assert.Equal(t, template.RestartRequirement.Weeks, updated.RestartRequirement.Weeks)
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
assert.Equal(t, template.FailureTTLMillis, updated.FailureTTLMillis)
@ -985,8 +985,8 @@ func TestTemplateEdit(t *testing.T) {
assert.Equal(t, template.Icon, updated.Icon)
assert.Equal(t, template.DisplayName, updated.DisplayName)
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
assert.Equal(t, template.RestartRequirement.DaysOfWeek, updated.RestartRequirement.DaysOfWeek)
assert.Equal(t, template.RestartRequirement.Weeks, updated.RestartRequirement.Weeks)
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
assert.Equal(t, template.FailureTTLMillis, updated.FailureTTLMillis)

View File

@ -26,7 +26,7 @@ func TestWorkspaceActivityBump(t *testing.T) {
ctx := context.Background()
// deadline allows you to forcibly set a max_deadline on the build. This
// doesn't use template restart requirements and instead edits the
// doesn't use template autostop requirements and instead edits the
// max_deadline on the build directly in the database.
setupActivityTest := func(t *testing.T, deadline ...time.Duration) (client *codersdk.Client, workspace codersdk.Workspace, assertBumped func(want bool)) {
const ttl = time.Minute
@ -49,7 +49,7 @@ func TestWorkspaceActivityBump(t *testing.T) {
UserAutostopEnabled: true,
DefaultTTL: ttl,
// We set max_deadline manually below.
RestartRequirement: schedule.TemplateRestartRequirement{},
AutostopRequirement: schedule.TemplateAutostopRequirement{},
}, nil
},
},

90
coderd/apidoc/docs.go generated
View File

@ -7390,6 +7390,14 @@ const docTemplate = `{
"description": "Allow users to cancel in-progress workspace jobs.\n*bool as the default value is \"true\".",
"type": "boolean"
},
"autostop_requirement": {
"description": "AutostopRequirement allows optionally specifying the autostop requirement\nfor workspaces created from this template. This is an enterprise feature.",
"allOf": [
{
"$ref": "#/definitions/codersdk.TemplateAutostopRequirement"
}
]
},
"default_ttl_ms": {
"description": "DefaultTTLMillis allows optionally specifying the default TTL\nfor all workspaces created from this template.",
"type": "integer"
@ -7423,21 +7431,13 @@ const docTemplate = `{
"type": "string"
},
"max_ttl_ms": {
"description": "TODO(@dean): remove max_ttl once restart_requirement is matured",
"description": "TODO(@dean): remove max_ttl once autostop_requirement is matured",
"type": "integer"
},
"name": {
"description": "Name is the name of the template.",
"type": "string"
},
"restart_requirement": {
"description": "RestartRequirement allows optionally specifying the restart requirement\nfor workspaces created from this template. This is an enterprise feature.",
"allOf": [
{
"$ref": "#/definitions/codersdk.TemplateRestartRequirement"
}
]
},
"template_version_id": {
"description": "VersionID is an in-progress or completed job to use as an initial version\nof the template.\n\nThis is required on creation to enable a user-flow of validating a\ntemplate works. There is no reason the data-model cannot support empty\ntemplates, but it doesn't make sense for users.",
"type": "string",
@ -8124,7 +8124,7 @@ const docTemplate = `{
"workspace_actions",
"tailnet_pg_coordinator",
"single_tailnet",
"template_restart_requirement",
"template_autostop_requirement",
"deployment_health_page",
"workspaces_batch_actions"
],
@ -8133,7 +8133,7 @@ const docTemplate = `{
"ExperimentWorkspaceActions",
"ExperimentTailnetPGCoordinator",
"ExperimentSingleTailnet",
"ExperimentTemplateRestartRequirement",
"ExperimentTemplateAutostopRequirement",
"ExperimentDeploymentHealthPage",
"ExperimentWorkspacesBatchActions"
]
@ -9516,6 +9516,14 @@ const docTemplate = `{
"allow_user_cancel_workspace_jobs": {
"type": "boolean"
},
"autostop_requirement": {
"description": "AutostopRequirement is an enterprise feature. Its value is only used if\nyour license is entitled to use the advanced template scheduling feature.",
"allOf": [
{
"$ref": "#/definitions/codersdk.TemplateAutostopRequirement"
}
]
},
"build_time_stats": {
"$ref": "#/definitions/codersdk.TemplateBuildTimeStats"
},
@ -9551,7 +9559,7 @@ const docTemplate = `{
"format": "uuid"
},
"max_ttl_ms": {
"description": "TODO(@dean): remove max_ttl once restart_requirement is matured",
"description": "TODO(@dean): remove max_ttl once autostop_requirement is matured",
"type": "integer"
},
"name": {
@ -9567,14 +9575,6 @@ const docTemplate = `{
"terraform"
]
},
"restart_requirement": {
"description": "RestartRequirement is an enterprise feature. Its value is only used if\nyour license is entitled to use the advanced template scheduling feature.",
"allOf": [
{
"$ref": "#/definitions/codersdk.TemplateRestartRequirement"
}
]
},
"time_til_dormant_autodelete_ms": {
"type": "integer"
},
@ -9633,6 +9633,31 @@ const docTemplate = `{
"TemplateAppsTypeApp"
]
},
"codersdk.TemplateAutostopRequirement": {
"type": "object",
"properties": {
"days_of_week": {
"description": "DaysOfWeek is a list of days of the week on which restarts are required.\nRestarts happen within the user's quiet hours (in their configured\ntimezone). If no days are specified, restarts are not required. Weekdays\ncannot be specified twice.\n\nRestarts will only happen on weekdays in this list on weeks which line up\nwith Weeks.",
"type": "array",
"items": {
"type": "string",
"enum": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday"
]
}
},
"weeks": {
"description": "Weeks is the number of weeks between required restarts. Weeks are synced\nacross all workspaces (and Coder deployments) using modulo math on a\nhardcoded epoch week of January 2nd, 2023 (the first Monday of 2023).\nValues of 0 or 1 indicate weekly restarts. Values of 2 indicate\nfortnightly restarts, etc.",
"type": "integer"
}
}
},
"codersdk.TemplateBuildTimeStats": {
"type": "object",
"additionalProperties": {
@ -9793,31 +9818,6 @@ const docTemplate = `{
}
}
},
"codersdk.TemplateRestartRequirement": {
"type": "object",
"properties": {
"days_of_week": {
"description": "DaysOfWeek is a list of days of the week on which restarts are required.\nRestarts happen within the user's quiet hours (in their configured\ntimezone). If no days are specified, restarts are not required. Weekdays\ncannot be specified twice.\n\nRestarts will only happen on weekdays in this list on weeks which line up\nwith Weeks.",
"type": "array",
"items": {
"type": "string",
"enum": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday"
]
}
},
"weeks": {
"description": "Weeks is the number of weeks between required restarts. Weeks are synced\nacross all workspaces (and Coder deployments) using modulo math on a\nhardcoded epoch week of January 2nd, 2023 (the first Monday of 2023).\nValues of 0 or 1 indicate weekly restarts. Values of 2 indicate\nfortnightly restarts, etc.",
"type": "integer"
}
}
},
"codersdk.TemplateRole": {
"type": "string",
"enum": [

View File

@ -6583,6 +6583,14 @@
"description": "Allow users to cancel in-progress workspace jobs.\n*bool as the default value is \"true\".",
"type": "boolean"
},
"autostop_requirement": {
"description": "AutostopRequirement allows optionally specifying the autostop requirement\nfor workspaces created from this template. This is an enterprise feature.",
"allOf": [
{
"$ref": "#/definitions/codersdk.TemplateAutostopRequirement"
}
]
},
"default_ttl_ms": {
"description": "DefaultTTLMillis allows optionally specifying the default TTL\nfor all workspaces created from this template.",
"type": "integer"
@ -6616,21 +6624,13 @@
"type": "string"
},
"max_ttl_ms": {
"description": "TODO(@dean): remove max_ttl once restart_requirement is matured",
"description": "TODO(@dean): remove max_ttl once autostop_requirement is matured",
"type": "integer"
},
"name": {
"description": "Name is the name of the template.",
"type": "string"
},
"restart_requirement": {
"description": "RestartRequirement allows optionally specifying the restart requirement\nfor workspaces created from this template. This is an enterprise feature.",
"allOf": [
{
"$ref": "#/definitions/codersdk.TemplateRestartRequirement"
}
]
},
"template_version_id": {
"description": "VersionID is an in-progress or completed job to use as an initial version\nof the template.\n\nThis is required on creation to enable a user-flow of validating a\ntemplate works. There is no reason the data-model cannot support empty\ntemplates, but it doesn't make sense for users.",
"type": "string",
@ -7275,7 +7275,7 @@
"workspace_actions",
"tailnet_pg_coordinator",
"single_tailnet",
"template_restart_requirement",
"template_autostop_requirement",
"deployment_health_page",
"workspaces_batch_actions"
],
@ -7284,7 +7284,7 @@
"ExperimentWorkspaceActions",
"ExperimentTailnetPGCoordinator",
"ExperimentSingleTailnet",
"ExperimentTemplateRestartRequirement",
"ExperimentTemplateAutostopRequirement",
"ExperimentDeploymentHealthPage",
"ExperimentWorkspacesBatchActions"
]
@ -8585,6 +8585,14 @@
"allow_user_cancel_workspace_jobs": {
"type": "boolean"
},
"autostop_requirement": {
"description": "AutostopRequirement is an enterprise feature. Its value is only used if\nyour license is entitled to use the advanced template scheduling feature.",
"allOf": [
{
"$ref": "#/definitions/codersdk.TemplateAutostopRequirement"
}
]
},
"build_time_stats": {
"$ref": "#/definitions/codersdk.TemplateBuildTimeStats"
},
@ -8620,7 +8628,7 @@
"format": "uuid"
},
"max_ttl_ms": {
"description": "TODO(@dean): remove max_ttl once restart_requirement is matured",
"description": "TODO(@dean): remove max_ttl once autostop_requirement is matured",
"type": "integer"
},
"name": {
@ -8634,14 +8642,6 @@
"type": "string",
"enum": ["terraform"]
},
"restart_requirement": {
"description": "RestartRequirement is an enterprise feature. Its value is only used if\nyour license is entitled to use the advanced template scheduling feature.",
"allOf": [
{
"$ref": "#/definitions/codersdk.TemplateRestartRequirement"
}
]
},
"time_til_dormant_autodelete_ms": {
"type": "integer"
},
@ -8694,6 +8694,31 @@
"enum": ["builtin", "app"],
"x-enum-varnames": ["TemplateAppsTypeBuiltin", "TemplateAppsTypeApp"]
},
"codersdk.TemplateAutostopRequirement": {
"type": "object",
"properties": {
"days_of_week": {
"description": "DaysOfWeek is a list of days of the week on which restarts are required.\nRestarts happen within the user's quiet hours (in their configured\ntimezone). If no days are specified, restarts are not required. Weekdays\ncannot be specified twice.\n\nRestarts will only happen on weekdays in this list on weeks which line up\nwith Weeks.",
"type": "array",
"items": {
"type": "string",
"enum": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday"
]
}
},
"weeks": {
"description": "Weeks is the number of weeks between required restarts. Weeks are synced\nacross all workspaces (and Coder deployments) using modulo math on a\nhardcoded epoch week of January 2nd, 2023 (the first Monday of 2023).\nValues of 0 or 1 indicate weekly restarts. Values of 2 indicate\nfortnightly restarts, etc.",
"type": "integer"
}
}
},
"codersdk.TemplateBuildTimeStats": {
"type": "object",
"additionalProperties": {
@ -8854,31 +8879,6 @@
}
}
},
"codersdk.TemplateRestartRequirement": {
"type": "object",
"properties": {
"days_of_week": {
"description": "DaysOfWeek is a list of days of the week on which restarts are required.\nRestarts happen within the user's quiet hours (in their configured\ntimezone). If no days are specified, restarts are not required. Weekdays\ncannot be specified twice.\n\nRestarts will only happen on weekdays in this list on weeks which line up\nwith Weeks.",
"type": "array",
"items": {
"type": "string",
"enum": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday"
]
}
},
"weeks": {
"description": "Weeks is the number of weeks between required restarts. Weeks are synced\nacross all workspaces (and Coder deployments) using modulo math on a\nhardcoded epoch week of January 2nd, 2023 (the first Monday of 2023).\nValues of 0 or 1 indicate weekly restarts. Values of 2 indicate\nfortnightly restarts, etc.",
"type": "integer"
}
}
},
"codersdk.TemplateRole": {
"type": "string",
"enum": ["admin", "use", ""],

View File

@ -623,7 +623,7 @@ func TestExecutorAutostartTemplateDisabled(t *testing.T) {
UserAutostartEnabled: false,
UserAutostopEnabled: true,
DefaultTTL: 0,
RestartRequirement: schedule.TemplateRestartRequirement{},
AutostopRequirement: schedule.TemplateAutostopRequirement{},
}, nil
},
},

View File

@ -5127,8 +5127,8 @@ func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database
tpl.UpdatedAt = database.Now()
tpl.DefaultTTL = arg.DefaultTTL
tpl.MaxTTL = arg.MaxTTL
tpl.RestartRequirementDaysOfWeek = arg.RestartRequirementDaysOfWeek
tpl.RestartRequirementWeeks = arg.RestartRequirementWeeks
tpl.AutostopRequirementDaysOfWeek = arg.AutostopRequirementDaysOfWeek
tpl.AutostopRequirementWeeks = arg.AutostopRequirementWeeks
tpl.FailureTTL = arg.FailureTTL
tpl.TimeTilDormant = arg.TimeTilDormant
tpl.TimeTilDormantAutoDelete = arg.TimeTilDormantAutoDelete

View File

@ -637,8 +637,8 @@ CREATE TABLE templates (
failure_ttl bigint DEFAULT 0 NOT NULL,
time_til_dormant bigint DEFAULT 0 NOT NULL,
time_til_dormant_autodelete bigint DEFAULT 0 NOT NULL,
restart_requirement_days_of_week smallint DEFAULT 0 NOT NULL,
restart_requirement_weeks bigint DEFAULT 0 NOT NULL
autostop_requirement_days_of_week smallint DEFAULT 0 NOT NULL,
autostop_requirement_weeks bigint DEFAULT 0 NOT NULL
);
COMMENT ON COLUMN templates.default_ttl IS 'The default duration for autostop for workspaces created from this template.';
@ -651,9 +651,9 @@ COMMENT ON COLUMN templates.allow_user_autostart IS 'Allow users to specify an a
COMMENT ON COLUMN templates.allow_user_autostop IS 'Allow users to specify custom autostop values for workspaces (enterprise).';
COMMENT ON COLUMN templates.restart_requirement_days_of_week IS 'A bitmap of days of week to restart the workspace on, starting with Monday as the 0th bit, and Sunday as the 6th bit. The 7th bit is unused.';
COMMENT ON COLUMN templates.autostop_requirement_days_of_week IS 'A bitmap of days of week to restart the workspace on, starting with Monday as the 0th bit, and Sunday as the 6th bit. The 7th bit is unused.';
COMMENT ON COLUMN templates.restart_requirement_weeks IS 'The number of weeks between restarts. 0 or 1 weeks means "every week", 2 week means "every second week", etc. Weeks are counted from January 2, 2023, which is the first Monday of 2023. This is to ensure workspaces are started consistently for all customers on the same n-week cycles.';
COMMENT ON COLUMN templates.autostop_requirement_weeks IS 'The number of weeks between restarts. 0 or 1 weeks means "every week", 2 week means "every second week", etc. Weeks are counted from January 2, 2023, which is the first Monday of 2023. This is to ensure workspaces are started consistently for all customers on the same n-week cycles.';
CREATE VIEW template_with_users AS
SELECT templates.id,
@ -678,8 +678,8 @@ CREATE VIEW template_with_users AS
templates.failure_ttl,
templates.time_til_dormant,
templates.time_til_dormant_autodelete,
templates.restart_requirement_days_of_week,
templates.restart_requirement_weeks,
templates.autostop_requirement_days_of_week,
templates.autostop_requirement_weeks,
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
COALESCE(visible_users.username, ''::text) AS created_by_username
FROM (public.templates

View File

@ -0,0 +1,7 @@
BEGIN;
ALTER TABLE templates RENAME COLUMN autostop_requirement_days_of_week TO restart_requirement_days_of_week;
ALTER TABLE templates RENAME COLUMN autostop_requirement_weeks TO restart_requirement_weeks;
COMMIT;

View File

@ -0,0 +1,25 @@
BEGIN;
ALTER TABLE templates RENAME COLUMN restart_requirement_days_of_week TO autostop_requirement_days_of_week;
ALTER TABLE templates RENAME COLUMN restart_requirement_weeks TO autostop_requirement_weeks;
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.';
COMMIT;

View File

@ -83,8 +83,8 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
&i.FailureTTL,
&i.TimeTilDormant,
&i.TimeTilDormantAutoDelete,
&i.RestartRequirementDaysOfWeek,
&i.RestartRequirementWeeks,
&i.AutostopRequirementDaysOfWeek,
&i.AutostopRequirementWeeks,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
); err != nil {

View File

@ -1709,32 +1709,32 @@ type TailnetCoordinator struct {
// Joins in the username + avatar url of the created by user.
type Template struct {
ID uuid.UUID `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
Deleted bool `db:"deleted" json:"deleted"`
Name string `db:"name" json:"name"`
Provisioner ProvisionerType `db:"provisioner" json:"provisioner"`
ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"`
Description string `db:"description" json:"description"`
DefaultTTL int64 `db:"default_ttl" json:"default_ttl"`
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
Icon string `db:"icon" json:"icon"`
UserACL TemplateACL `db:"user_acl" json:"user_acl"`
GroupACL TemplateACL `db:"group_acl" json:"group_acl"`
DisplayName string `db:"display_name" json:"display_name"`
AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"`
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
AllowUserAutostart bool `db:"allow_user_autostart" json:"allow_user_autostart"`
AllowUserAutostop bool `db:"allow_user_autostop" json:"allow_user_autostop"`
FailureTTL int64 `db:"failure_ttl" json:"failure_ttl"`
TimeTilDormant int64 `db:"time_til_dormant" json:"time_til_dormant"`
TimeTilDormantAutoDelete int64 `db:"time_til_dormant_autodelete" json:"time_til_dormant_autodelete"`
RestartRequirementDaysOfWeek int16 `db:"restart_requirement_days_of_week" json:"restart_requirement_days_of_week"`
RestartRequirementWeeks int64 `db:"restart_requirement_weeks" json:"restart_requirement_weeks"`
CreatedByAvatarURL sql.NullString `db:"created_by_avatar_url" json:"created_by_avatar_url"`
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
ID uuid.UUID `db:"id" json:"id"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
Deleted bool `db:"deleted" json:"deleted"`
Name string `db:"name" json:"name"`
Provisioner ProvisionerType `db:"provisioner" json:"provisioner"`
ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"`
Description string `db:"description" json:"description"`
DefaultTTL int64 `db:"default_ttl" json:"default_ttl"`
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
Icon string `db:"icon" json:"icon"`
UserACL TemplateACL `db:"user_acl" json:"user_acl"`
GroupACL TemplateACL `db:"group_acl" json:"group_acl"`
DisplayName string `db:"display_name" json:"display_name"`
AllowUserCancelWorkspaceJobs bool `db:"allow_user_cancel_workspace_jobs" json:"allow_user_cancel_workspace_jobs"`
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
AllowUserAutostart bool `db:"allow_user_autostart" json:"allow_user_autostart"`
AllowUserAutostop bool `db:"allow_user_autostop" json:"allow_user_autostop"`
FailureTTL int64 `db:"failure_ttl" json:"failure_ttl"`
TimeTilDormant int64 `db:"time_til_dormant" json:"time_til_dormant"`
TimeTilDormantAutoDelete int64 `db:"time_til_dormant_autodelete" json:"time_til_dormant_autodelete"`
AutostopRequirementDaysOfWeek int16 `db:"autostop_requirement_days_of_week" json:"autostop_requirement_days_of_week"`
AutostopRequirementWeeks int64 `db:"autostop_requirement_weeks" json:"autostop_requirement_weeks"`
CreatedByAvatarURL sql.NullString `db:"created_by_avatar_url" json:"created_by_avatar_url"`
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
}
type TemplateTable struct {
@ -1766,9 +1766,9 @@ type TemplateTable struct {
TimeTilDormant int64 `db:"time_til_dormant" json:"time_til_dormant"`
TimeTilDormantAutoDelete int64 `db:"time_til_dormant_autodelete" json:"time_til_dormant_autodelete"`
// A bitmap of days of week to restart the workspace on, starting with Monday as the 0th bit, and Sunday as the 6th bit. The 7th bit is unused.
RestartRequirementDaysOfWeek int16 `db:"restart_requirement_days_of_week" json:"restart_requirement_days_of_week"`
AutostopRequirementDaysOfWeek int16 `db:"autostop_requirement_days_of_week" json:"autostop_requirement_days_of_week"`
// The number of weeks between restarts. 0 or 1 weeks means "every week", 2 week means "every second week", etc. Weeks are counted from January 2, 2023, which is the first Monday of 2023. This is to ensure workspaces are started consistently for all customers on the same n-week cycles.
RestartRequirementWeeks int64 `db:"restart_requirement_weeks" json:"restart_requirement_weeks"`
AutostopRequirementWeeks int64 `db:"autostop_requirement_weeks" json:"autostop_requirement_weeks"`
}
// Joins in the username + avatar url of the created by user.

View File

@ -4317,7 +4317,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, restart_requirement_days_of_week, restart_requirement_weeks, 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, created_by_avatar_url, created_by_username
FROM
template_with_users
WHERE
@ -4352,8 +4352,8 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
&i.FailureTTL,
&i.TimeTilDormant,
&i.TimeTilDormantAutoDelete,
&i.RestartRequirementDaysOfWeek,
&i.RestartRequirementWeeks,
&i.AutostopRequirementDaysOfWeek,
&i.AutostopRequirementWeeks,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
)
@ -4362,7 +4362,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, restart_requirement_days_of_week, restart_requirement_weeks, 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, created_by_avatar_url, created_by_username
FROM
template_with_users AS templates
WHERE
@ -4405,8 +4405,8 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
&i.FailureTTL,
&i.TimeTilDormant,
&i.TimeTilDormantAutoDelete,
&i.RestartRequirementDaysOfWeek,
&i.RestartRequirementWeeks,
&i.AutostopRequirementDaysOfWeek,
&i.AutostopRequirementWeeks,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
)
@ -4414,7 +4414,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, restart_requirement_days_of_week, restart_requirement_weeks, 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, created_by_avatar_url, created_by_username FROM template_with_users AS templates
ORDER BY (name, id) ASC
`
@ -4450,8 +4450,8 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
&i.FailureTTL,
&i.TimeTilDormant,
&i.TimeTilDormantAutoDelete,
&i.RestartRequirementDaysOfWeek,
&i.RestartRequirementWeeks,
&i.AutostopRequirementDaysOfWeek,
&i.AutostopRequirementWeeks,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
); err != nil {
@ -4470,7 +4470,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, restart_requirement_days_of_week, restart_requirement_weeks, 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, created_by_avatar_url, created_by_username
FROM
template_with_users AS templates
WHERE
@ -4543,8 +4543,8 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
&i.FailureTTL,
&i.TimeTilDormant,
&i.TimeTilDormantAutoDelete,
&i.RestartRequirementDaysOfWeek,
&i.RestartRequirementWeeks,
&i.AutostopRequirementDaysOfWeek,
&i.AutostopRequirementWeeks,
&i.CreatedByAvatarURL,
&i.CreatedByUsername,
); err != nil {
@ -4729,8 +4729,8 @@ SET
allow_user_autostop = $4,
default_ttl = $5,
max_ttl = $6,
restart_requirement_days_of_week = $7,
restart_requirement_weeks = $8,
autostop_requirement_days_of_week = $7,
autostop_requirement_weeks = $8,
failure_ttl = $9,
time_til_dormant = $10,
time_til_dormant_autodelete = $11
@ -4739,17 +4739,17 @@ WHERE
`
type UpdateTemplateScheduleByIDParams struct {
ID uuid.UUID `db:"id" json:"id"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
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"`
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
RestartRequirementDaysOfWeek int16 `db:"restart_requirement_days_of_week" json:"restart_requirement_days_of_week"`
RestartRequirementWeeks int64 `db:"restart_requirement_weeks" json:"restart_requirement_weeks"`
FailureTTL int64 `db:"failure_ttl" json:"failure_ttl"`
TimeTilDormant int64 `db:"time_til_dormant" json:"time_til_dormant"`
TimeTilDormantAutoDelete int64 `db:"time_til_dormant_autodelete" json:"time_til_dormant_autodelete"`
ID uuid.UUID `db:"id" json:"id"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
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"`
MaxTTL int64 `db:"max_ttl" json:"max_ttl"`
AutostopRequirementDaysOfWeek int16 `db:"autostop_requirement_days_of_week" json:"autostop_requirement_days_of_week"`
AutostopRequirementWeeks int64 `db:"autostop_requirement_weeks" json:"autostop_requirement_weeks"`
FailureTTL int64 `db:"failure_ttl" json:"failure_ttl"`
TimeTilDormant int64 `db:"time_til_dormant" json:"time_til_dormant"`
TimeTilDormantAutoDelete int64 `db:"time_til_dormant_autodelete" json:"time_til_dormant_autodelete"`
}
func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateTemplateScheduleByIDParams) error {
@ -4760,8 +4760,8 @@ func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateT
arg.AllowUserAutostop,
arg.DefaultTTL,
arg.MaxTTL,
arg.RestartRequirementDaysOfWeek,
arg.RestartRequirementWeeks,
arg.AutostopRequirementDaysOfWeek,
arg.AutostopRequirementWeeks,
arg.FailureTTL,
arg.TimeTilDormant,
arg.TimeTilDormantAutoDelete,

View File

@ -118,8 +118,8 @@ SET
allow_user_autostop = $4,
default_ttl = $5,
max_ttl = $6,
restart_requirement_days_of_week = $7,
restart_requirement_weeks = $8,
autostop_requirement_days_of_week = $7,
autostop_requirement_weeks = $8,
failure_ttl = $9,
time_til_dormant = $10,
time_til_dormant_autodelete = $11

View File

@ -1027,11 +1027,11 @@ func TestCompleteJob(t *testing.T) {
var store schedule.TemplateScheduleStore = schedule.MockTemplateScheduleStore{
GetFn: func(_ context.Context, _ database.Store, _ uuid.UUID) (schedule.TemplateScheduleOptions, error) {
return schedule.TemplateScheduleOptions{
UserAutostartEnabled: false,
UserAutostopEnabled: c.templateAllowAutostop,
DefaultTTL: c.templateDefaultTTL,
MaxTTL: c.templateMaxTTL,
UseRestartRequirement: false,
UserAutostartEnabled: false,
UserAutostopEnabled: c.templateAllowAutostop,
DefaultTTL: c.templateDefaultTTL,
MaxTTL: c.templateMaxTTL,
UseAutostopRequirement: false,
}, nil
},
}
@ -1155,7 +1155,7 @@ func TestCompleteJob(t *testing.T) {
// Wednesday the 8th of February 2023 at midnight. This date was
// specifically chosen as it doesn't fall on a applicable week for both
// fortnightly and triweekly restart requirements.
// fortnightly and triweekly autostop requirements.
wednesdayMidnightUTC := time.Date(2023, 2, 8, 0, 0, 0, 0, time.UTC)
sydneyQuietHours := "CRON_TZ=Australia/Sydney 0 0 * * *"
@ -1175,44 +1175,44 @@ func TestCompleteJob(t *testing.T) {
transition database.WorkspaceTransition
// These fields are only used when testing max deadline.
userQuietHoursSchedule string
templateRestartRequirement schedule.TemplateRestartRequirement
userQuietHoursSchedule string
templateAutostopRequirement schedule.TemplateAutostopRequirement
expectedDeadline time.Time
expectedMaxDeadline time.Time
}{
{
name: "OK",
now: now,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: 0,
transition: database.WorkspaceTransitionStart,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
name: "OK",
now: now,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: 0,
transition: database.WorkspaceTransitionStart,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
},
{
name: "Delete",
now: now,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: 0,
transition: database.WorkspaceTransitionDelete,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
name: "Delete",
now: now,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: 0,
transition: database.WorkspaceTransitionDelete,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
},
{
name: "WorkspaceTTL",
now: now,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: time.Hour,
transition: database.WorkspaceTransitionStart,
expectedDeadline: now.Add(time.Hour),
expectedMaxDeadline: time.Time{},
name: "WorkspaceTTL",
now: now,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: time.Hour,
transition: database.WorkspaceTransitionStart,
expectedDeadline: now.Add(time.Hour),
expectedMaxDeadline: time.Time{},
},
{
name: "TemplateRestartRequirement",
name: "TemplateAutostopRequirement",
now: wednesdayMidnightUTC,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 0, // weekly
},
@ -1241,11 +1241,11 @@ func TestCompleteJob(t *testing.T) {
var templateScheduleStore schedule.TemplateScheduleStore = schedule.MockTemplateScheduleStore{
GetFn: func(_ context.Context, _ database.Store, _ uuid.UUID) (schedule.TemplateScheduleOptions, error) {
return schedule.TemplateScheduleOptions{
UserAutostartEnabled: false,
UserAutostopEnabled: true,
DefaultTTL: 0,
UseRestartRequirement: true,
RestartRequirement: c.templateRestartRequirement,
UserAutostartEnabled: false,
UserAutostopEnabled: true,
DefaultTTL: 0,
UseAutostopRequirement: true,
AutostopRequirement: c.templateAutostopRequirement,
}, nil
},
}
@ -1280,13 +1280,13 @@ func TestCompleteJob(t *testing.T) {
Provisioner: database.ProvisionerTypeEcho,
})
err := srv.Database.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: false,
AllowUserAutostop: true,
DefaultTTL: 0,
RestartRequirementDaysOfWeek: int16(c.templateRestartRequirement.DaysOfWeek),
RestartRequirementWeeks: c.templateRestartRequirement.Weeks,
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: false,
AllowUserAutostop: true,
DefaultTTL: 0,
AutostopRequirementDaysOfWeek: int16(c.templateAutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: c.templateAutostopRequirement.Weeks,
})
require.NoError(t, err)
template, err = srv.Database.GetTemplateByID(ctx, template.ID)

View File

@ -13,17 +13,17 @@ import (
)
const (
// restartRequirementLeeway is the duration of time before a restart
// autostopRequirementLeeway is the duration of time before a autostop
// requirement where we skip the requirement and fall back to the next
// scheduled restart. This avoids workspaces being restarted too soon.
// scheduled stop. This avoids workspaces being stopped too soon.
//
// E.g. If the workspace is started within an hour of the quiet hours, we
// will skip the restart requirement and use the next scheduled restart
// requirement.
restartRequirementLeeway = 1 * time.Hour
// will skip the autostop requirement and use the next scheduled
// stop time instead.
autostopRequirementLeeway = 1 * time.Hour
// restartRequirementBuffer is the duration of time we subtract from the
// time when calculating the next scheduled restart time. This avoids issues
// autostopRequirementBuffer is the duration of time we subtract from the
// time when calculating the next scheduled stop time. This avoids issues
// where autostart happens on the hour and the scheduled quiet hours are
// also on the hour.
//
@ -37,7 +37,7 @@ const (
//
// This resolves that problem by subtracting 15 minutes from midnight
// when we check the next cron time.
restartRequirementBuffer = -15 * time.Minute
autostopRequirementBuffer = -15 * time.Minute
)
type CalculateAutostopParams struct {
@ -68,7 +68,7 @@ type AutostopTime struct {
//
// MaxDeadline is the maximum value for deadline. The deadline cannot be bumped
// past this value, so it denotes the absolute deadline that the workspace build
// must be stopped by. MaxDeadline is calculated using the template's "restart
// must be stopped by. MaxDeadline is calculated using the template's "autostop
// requirement" settings and the user's "quiet hours" settings to pick a time
// outside of working hours.
//
@ -113,13 +113,13 @@ func CalculateAutostop(ctx context.Context, params CalculateAutostopParams) (Aut
// Use the old algorithm for calculating max_deadline if the instance isn't
// configured or entitled to use the new feature flag yet.
// TODO(@dean): remove this once the feature flag is enabled for all
if !templateSchedule.UseRestartRequirement && templateSchedule.MaxTTL > 0 {
if !templateSchedule.UseAutostopRequirement && templateSchedule.MaxTTL > 0 {
autostop.MaxDeadline = now.Add(templateSchedule.MaxTTL)
}
// TODO(@dean): remove extra conditional
if templateSchedule.UseRestartRequirement && templateSchedule.RestartRequirement.DaysOfWeek != 0 {
// The template has a restart requirement, so determine the max deadline
if templateSchedule.UseAutostopRequirement && templateSchedule.AutostopRequirement.DaysOfWeek != 0 {
// The template has a autostop requirement, so determine the max deadline
// of this workspace build.
// First, get the user's quiet hours schedule (this will return the
@ -137,13 +137,13 @@ func CalculateAutostop(ctx context.Context, params CalculateAutostopParams) (Aut
now := now.In(loc)
// Add the leeway here so we avoid checking today's quiet hours if
// the workspace was started <1h before midnight.
startOfStopDay := truncateMidnight(now.Add(restartRequirementLeeway))
startOfStopDay := truncateMidnight(now.Add(autostopRequirementLeeway))
// If the template schedule wants to only restart on n-th weeks then
// change the startOfDay to be the Monday of the next applicable
// week.
if templateSchedule.RestartRequirement.Weeks > 1 {
startOfStopDay, err = GetNextApplicableMondayOfNWeeks(startOfStopDay, templateSchedule.RestartRequirement.Weeks)
// If the template schedule wants to only autostop on n-th weeks
// then change the startOfDay to be the Monday of the next
// applicable week.
if templateSchedule.AutostopRequirement.Weeks > 1 {
startOfStopDay, err = GetNextApplicableMondayOfNWeeks(startOfStopDay, templateSchedule.AutostopRequirement.Weeks)
if err != nil {
return autostop, xerrors.Errorf("determine start of stop week: %w", err)
}
@ -155,30 +155,30 @@ func CalculateAutostop(ctx context.Context, params CalculateAutostopParams) (Aut
// Allow an hour of leeway (i.e. any workspaces started within an
// hour of the scheduled stop time will always bounce to the next
// stop window).
checkSchedule := userQuietHoursSchedule.Schedule.Next(startOfStopDay.Add(restartRequirementBuffer))
if checkSchedule.Before(now.Add(restartRequirementLeeway)) {
checkSchedule := userQuietHoursSchedule.Schedule.Next(startOfStopDay.Add(autostopRequirementBuffer))
if checkSchedule.Before(now.Add(autostopRequirementLeeway)) {
// Set the first stop day we try to tomorrow because today's
// schedule is too close to now or has already passed.
startOfStopDay = nextDayMidnight(startOfStopDay)
}
// Iterate from 0 to 7, check if the current startOfDay is in the
// restart requirement. If it isn't then add a day and try again.
requirementDays := templateSchedule.RestartRequirement.DaysMap()
// autostop requirement. If it isn't then add a day and try again.
requirementDays := templateSchedule.AutostopRequirement.DaysMap()
for i := 0; i < len(DaysOfWeek)+1; i++ {
if i == len(DaysOfWeek) {
// We've wrapped, so somehow we couldn't find a day in the
// restart requirement in the next week.
// autostop requirement in the next week.
//
// This shouldn't be able to happen, as we've already
// checked that there is a day in the restart requirement
// checked that there is a day in the autostop requirement
// above with the
// `if templateSchedule.RestartRequirement.DaysOfWeek != 0`
// `if templateSchedule.AutoStopRequirement.DaysOfWeek != 0`
// check.
//
// The eighth bit shouldn't be set, as we validate the
// bitmap in the enterprise TemplateScheduleStore.
return autostop, xerrors.New("could not find suitable day for template restart requirement in the next 7 days")
return autostop, xerrors.New("could not find suitable day for template autostop requirement in the next 7 days")
}
if requirementDays[startOfStopDay.Weekday()] {
break
@ -194,13 +194,13 @@ func CalculateAutostop(ctx context.Context, params CalculateAutostopParams) (Aut
// If it's not within an hour of now, subtract 15 minutes to
// give a little leeway. This prevents skipped stop events
// because autostart perfectly lines up with autostop.
checkTime = checkTime.Add(restartRequirementBuffer)
checkTime = checkTime.Add(autostopRequirementBuffer)
}
// Get the next occurrence of the restart schedule.
// Get the next occurrence of the schedule.
autostop.MaxDeadline = userQuietHoursSchedule.Schedule.Next(checkTime)
if autostop.MaxDeadline.IsZero() {
return autostop, xerrors.New("could not find next occurrence of template restart requirement in user quiet hours schedule")
return autostop, xerrors.Errorf("could not find next occurrence of template autostop requirement in user quiet hours schedule, checked from time %q", checkTime)
}
}
}
@ -244,9 +244,9 @@ func nextDayMidnight(t time.Time) time.Time {
//
// The timezone embedded in the time object is used to determine the epoch.
func WeeksSinceEpoch(now time.Time) (int64, error) {
epoch := TemplateRestartRequirementEpoch(now.Location())
epoch := TemplateAutostopRequirementEpoch(now.Location())
if now.Before(epoch) {
return 0, xerrors.New("coder server system clock is incorrect, cannot calculate template restart requirement")
return 0, xerrors.New("coder server system clock is incorrect, cannot calculate template autostop requirement")
}
// This calculation needs to be done using YearDay, as dividing by the
@ -290,7 +290,7 @@ func GetMondayOfWeek(loc *time.Location, n int64) (time.Time, error) {
if n < 0 {
return time.Time{}, xerrors.New("weeks since epoch must be positive")
}
epoch := TemplateRestartRequirementEpoch(loc)
epoch := TemplateAutostopRequirementEpoch(loc)
monday := epoch.AddDate(0, 0, int(n*7))
y, m, d := monday.Date()

View File

@ -25,7 +25,7 @@ func TestCalculateAutoStop(t *testing.T) {
// Wednesday the 8th of February 2023 at midnight. This date was
// specifically chosen as it doesn't fall on a applicable week for both
// fortnightly and triweekly restart requirements.
// fortnightly and triweekly autostop requirements.
wednesdayMidnightUTC := time.Date(2023, 2, 8, 0, 0, 0, 0, time.UTC)
sydneyQuietHours := "CRON_TZ=Australia/Sydney 0 0 * * *"
@ -73,10 +73,10 @@ func TestCalculateAutoStop(t *testing.T) {
templateAllowAutostop bool
templateDefaultTTL time.Duration
// TODO(@dean): remove max_ttl tests
useMaxTTL bool
templateMaxTTL time.Duration
templateRestartRequirement schedule.TemplateRestartRequirement
userQuietHoursSchedule string
useMaxTTL bool
templateMaxTTL time.Duration
templateAutostopRequirement schedule.TemplateAutostopRequirement
userQuietHoursSchedule string
// workspaceTTL is usually copied from the template's TTL when the
// workspace is made, so it takes precedence unless
// templateAllowAutostop is false.
@ -88,72 +88,72 @@ func TestCalculateAutoStop(t *testing.T) {
errContains string
}{
{
name: "OK",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: 0,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: 0,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
name: "OK",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: 0,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: 0,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
},
{
name: "Delete",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: 0,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: 0,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
name: "Delete",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: 0,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: 0,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
},
{
name: "WorkspaceTTL",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: 0,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: time.Hour,
expectedDeadline: now.Add(time.Hour),
expectedMaxDeadline: time.Time{},
name: "WorkspaceTTL",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: 0,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: time.Hour,
expectedDeadline: now.Add(time.Hour),
expectedMaxDeadline: time.Time{},
},
{
name: "TemplateDefaultTTLIgnored",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: time.Hour,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: 0,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
name: "TemplateDefaultTTLIgnored",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: time.Hour,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: 0,
expectedDeadline: time.Time{},
expectedMaxDeadline: time.Time{},
},
{
name: "WorkspaceTTLOverridesTemplateDefaultTTL",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: 2 * time.Hour,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: time.Hour,
expectedDeadline: now.Add(time.Hour),
expectedMaxDeadline: time.Time{},
name: "WorkspaceTTLOverridesTemplateDefaultTTL",
now: now,
templateAllowAutostop: true,
templateDefaultTTL: 2 * time.Hour,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: time.Hour,
expectedDeadline: now.Add(time.Hour),
expectedMaxDeadline: time.Time{},
},
{
name: "TemplateBlockWorkspaceTTL",
now: now,
templateAllowAutostop: false,
templateDefaultTTL: 3 * time.Hour,
templateRestartRequirement: schedule.TemplateRestartRequirement{},
workspaceTTL: 4 * time.Hour,
expectedDeadline: now.Add(3 * time.Hour),
expectedMaxDeadline: time.Time{},
name: "TemplateBlockWorkspaceTTL",
now: now,
templateAllowAutostop: false,
templateDefaultTTL: 3 * time.Hour,
templateAutostopRequirement: schedule.TemplateAutostopRequirement{},
workspaceTTL: 4 * time.Hour,
expectedDeadline: now.Add(3 * time.Hour),
expectedMaxDeadline: time.Time{},
},
{
name: "TemplateRestartRequirement",
name: "TemplateAutostopRequirement",
now: wednesdayMidnightUTC,
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 0, // weekly
},
@ -162,12 +162,12 @@ func TestCalculateAutoStop(t *testing.T) {
expectedMaxDeadline: saturdayMidnightSydney.In(time.UTC),
},
{
name: "TemplateRestartRequirement1HourSkip",
name: "TemplateAutostopRequirement1HourSkip",
now: saturdayMidnightSydney.Add(-59 * time.Minute),
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 1, // 1 also means weekly
},
@ -176,14 +176,14 @@ func TestCalculateAutoStop(t *testing.T) {
expectedMaxDeadline: saturdayMidnightSydney.Add(7 * 24 * time.Hour).In(time.UTC),
},
{
// The next restart requirement should be skipped if the
// The next autostop requirement should be skipped if the
// workspace is started within 1 hour of it.
name: "TemplateRestartRequirementDaily",
name: "TemplateAutostopRequirementDaily",
now: fridayEveningSydney,
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b01111111, // daily
Weeks: 0, // all weeks
},
@ -192,12 +192,12 @@ func TestCalculateAutoStop(t *testing.T) {
expectedMaxDeadline: saturdayMidnightSydney.In(time.UTC),
},
{
name: "TemplateRestartRequirementFortnightly/Skip",
name: "TemplateAutostopRequirementFortnightly/Skip",
now: wednesdayMidnightUTC,
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 2, // every 2 weeks
},
@ -206,12 +206,12 @@ func TestCalculateAutoStop(t *testing.T) {
expectedMaxDeadline: saturdayMidnightSydney.AddDate(0, 0, 7).In(time.UTC),
},
{
name: "TemplateRestartRequirementFortnightly/NoSkip",
name: "TemplateAutostopRequirementFortnightly/NoSkip",
now: wednesdayMidnightUTC.AddDate(0, 0, 7),
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 2, // every 2 weeks
},
@ -220,28 +220,28 @@ func TestCalculateAutoStop(t *testing.T) {
expectedMaxDeadline: saturdayMidnightSydney.AddDate(0, 0, 7).In(time.UTC),
},
{
name: "TemplateRestartRequirementTriweekly/Skip",
name: "TemplateAutostopRequirementTriweekly/Skip",
now: wednesdayMidnightUTC,
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 3, // every 3 weeks
},
workspaceTTL: 0,
// expectedDeadline is copied from expectedMaxDeadline.
// The next triweekly restart requirement happens next week
// The next triweekly autostop requirement happens next week
// according to the epoch.
expectedMaxDeadline: saturdayMidnightSydney.AddDate(0, 0, 7).In(time.UTC),
},
{
name: "TemplateRestartRequirementTriweekly/NoSkip",
name: "TemplateAutostopRequirementTriweekly/NoSkip",
now: wednesdayMidnightUTC.AddDate(0, 0, 7),
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 3, // every 3 weeks
},
@ -250,14 +250,14 @@ func TestCalculateAutoStop(t *testing.T) {
expectedMaxDeadline: saturdayMidnightSydney.AddDate(0, 0, 7).In(time.UTC),
},
{
name: "TemplateRestartRequirementOverridesWorkspaceTTL",
name: "TemplateAutostopRequirementOverridesWorkspaceTTL",
// now doesn't have to be UTC, but it helps us ensure that
// timezones are compared correctly in this test.
now: fridayEveningSydney.In(time.UTC),
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 0, // weekly
},
@ -266,12 +266,12 @@ func TestCalculateAutoStop(t *testing.T) {
expectedMaxDeadline: saturdayMidnightSydney.In(time.UTC),
},
{
name: "TemplateRestartRequirementOverridesTemplateDefaultTTL",
name: "TemplateAutostopRequirementOverridesTemplateDefaultTTL",
now: fridayEveningSydney.In(time.UTC),
templateAllowAutostop: true,
templateDefaultTTL: 3 * time.Hour,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 0, // weekly
},
@ -288,7 +288,7 @@ func TestCalculateAutoStop(t *testing.T) {
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 2, // every fortnight
},
@ -301,7 +301,7 @@ func TestCalculateAutoStop(t *testing.T) {
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 1, // weekly
},
@ -315,7 +315,7 @@ func TestCalculateAutoStop(t *testing.T) {
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 1, // weekly
},
@ -329,7 +329,7 @@ func TestCalculateAutoStop(t *testing.T) {
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 1, // weekly
},
@ -343,7 +343,7 @@ func TestCalculateAutoStop(t *testing.T) {
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: dstInQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b01000000, // Sunday
Weeks: 1, // weekly
},
@ -357,7 +357,7 @@ func TestCalculateAutoStop(t *testing.T) {
templateAllowAutostop: true,
templateDefaultTTL: 0,
userQuietHoursSchedule: dstOutQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b01000000, // Sunday
Weeks: 1, // weekly
},
@ -368,14 +368,14 @@ func TestCalculateAutoStop(t *testing.T) {
// TODO(@dean): remove max_ttl tests
{
name: "RestartRequirementIgnoresMaxTTL",
name: "AutostopRequirementIgnoresMaxTTL",
now: fridayEveningSydney.In(time.UTC),
templateAllowAutostop: false,
templateDefaultTTL: 0,
useMaxTTL: false,
templateMaxTTL: time.Hour, // should be ignored
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 0, // weekly
},
@ -384,14 +384,14 @@ func TestCalculateAutoStop(t *testing.T) {
expectedMaxDeadline: saturdayMidnightSydney.In(time.UTC),
},
{
name: "MaxTTLIgnoresRestartRequirement",
name: "MaxTTLIgnoresAutostopRequirement",
now: fridayEveningSydney.In(time.UTC),
templateAllowAutostop: false,
templateDefaultTTL: 0,
useMaxTTL: true,
templateMaxTTL: time.Hour, // should NOT be ignored
userQuietHoursSchedule: sydneyQuietHours,
templateRestartRequirement: schedule.TemplateRestartRequirement{
templateAutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: 0b00100000, // Saturday
Weeks: 0, // weekly
},
@ -413,12 +413,12 @@ func TestCalculateAutoStop(t *testing.T) {
templateScheduleStore := schedule.MockTemplateScheduleStore{
GetFn: func(_ context.Context, _ database.Store, _ uuid.UUID) (schedule.TemplateScheduleOptions, error) {
return schedule.TemplateScheduleOptions{
UserAutostartEnabled: false,
UserAutostopEnabled: c.templateAllowAutostop,
DefaultTTL: c.templateDefaultTTL,
MaxTTL: c.templateMaxTTL,
UseRestartRequirement: !c.useMaxTTL,
RestartRequirement: c.templateRestartRequirement,
UserAutostartEnabled: false,
UserAutostopEnabled: c.templateAllowAutostop,
DefaultTTL: c.templateDefaultTTL,
MaxTTL: c.templateMaxTTL,
UseAutostopRequirement: !c.useMaxTTL,
AutostopRequirement: c.templateAutostopRequirement,
}, nil
},
}
@ -454,11 +454,11 @@ func TestCalculateAutoStop(t *testing.T) {
CreatedBy: user.ID,
})
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: c.templateAllowAutostop,
RestartRequirementDaysOfWeek: int16(c.templateRestartRequirement.DaysOfWeek),
RestartRequirementWeeks: c.templateRestartRequirement.Weeks,
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: c.templateAllowAutostop,
AutostopRequirementDaysOfWeek: int16(c.templateAutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: c.templateAutostopRequirement.Weeks,
})
require.NoError(t, err)
template, err = db.GetTemplateByID(ctx, template.ID)

View File

@ -11,9 +11,9 @@ import (
"github.com/coder/coder/v2/coderd/tracing"
)
const MaxTemplateRestartRequirementWeeks = 16
const MaxTemplateAutostopRequirementWeeks = 16
func TemplateRestartRequirementEpoch(loc *time.Location) time.Time {
func TemplateAutostopRequirementEpoch(loc *time.Location) time.Time {
// The "first week" starts on January 2nd, 2023, which is the first Monday
// of 2023. All other weeks are counted using modulo arithmetic from that
// date.
@ -34,7 +34,7 @@ var DaysOfWeek = []time.Weekday{
time.Sunday,
}
type TemplateRestartRequirement struct {
type TemplateAutostopRequirement struct {
// DaysOfWeek is a bitmap of which days of the week the workspace must be
// restarted. If fully zero, the workspace is not required to be restarted
// ever.
@ -55,7 +55,7 @@ type TemplateRestartRequirement struct {
// DaysMap returns a map of the days of the week that the workspace must be
// restarted.
func (r TemplateRestartRequirement) DaysMap() map[time.Weekday]bool {
func (r TemplateAutostopRequirement) DaysMap() map[time.Weekday]bool {
days := make(map[time.Weekday]bool)
for i, day := range DaysOfWeek {
days[day] = r.DaysOfWeek&(1<<uint(i)) != 0
@ -63,20 +63,20 @@ func (r TemplateRestartRequirement) DaysMap() map[time.Weekday]bool {
return days
}
// VerifyTemplateRestartRequirement returns an error if the restart requirement
// is invalid.
func VerifyTemplateRestartRequirement(days uint8, weeks int64) error {
// VerifyTemplateAutostopRequirement returns an error if the autostop
// requirement is invalid.
func VerifyTemplateAutostopRequirement(days uint8, weeks int64) error {
if days&0b10000000 != 0 {
return xerrors.New("invalid restart requirement days, last bit is set")
return xerrors.New("invalid autostop requirement days, last bit is set")
}
if days > 0b11111111 {
return xerrors.New("invalid restart requirement days, too large")
return xerrors.New("invalid autostop requirement days, too large")
}
if weeks < 0 {
return xerrors.New("invalid restart requirement weeks, negative")
return xerrors.New("invalid autostop requirement weeks, negative")
}
if weeks > MaxTemplateRestartRequirementWeeks {
return xerrors.New("invalid restart requirement weeks, too large")
if weeks > MaxTemplateAutostopRequirementWeeks {
return xerrors.New("invalid autostop requirement weeks, too large")
}
return nil
}
@ -85,17 +85,17 @@ type TemplateScheduleOptions struct {
UserAutostartEnabled bool `json:"user_autostart_enabled"`
UserAutostopEnabled bool `json:"user_autostop_enabled"`
DefaultTTL time.Duration `json:"default_ttl"`
// TODO(@dean): remove MaxTTL once restart_requirement is matured and the
// TODO(@dean): remove MaxTTL once autostop_requirement is matured and the
// default
MaxTTL time.Duration `json:"max_ttl"`
// UseRestartRequirement dictates whether the restart requirement should be
// used instead of MaxTTL. This is governed by the feature flag and
// UseAutostopRequirement dictates whether the autostop requirement should
// be used instead of MaxTTL. This is governed by the feature flag and
// licensing.
// TODO(@dean): remove this when we remove max_tll
UseRestartRequirement bool
// RestartRequirement dictates when the workspace must be restarted. This
UseAutostopRequirement bool
// AutostopRequirement dictates when the workspace must be restarted. This
// used to be handled by MaxTTL.
RestartRequirement TemplateRestartRequirement `json:"restart_requirement"`
AutostopRequirement TemplateAutostopRequirement `json:"autostop_requirement"`
// FailureTTL dictates the duration after which failed workspaces will be
// stopped automatically.
FailureTTL time.Duration `json:"failure_ttl"`
@ -149,11 +149,11 @@ func (*agplTemplateScheduleStore) Get(ctx context.Context, db database.Store, te
UserAutostartEnabled: true,
UserAutostopEnabled: true,
DefaultTTL: time.Duration(tpl.DefaultTTL),
// Disregard the values in the database, since RestartRequirement,
// Disregard the values in the database, since AutostopRequirement,
// FailureTTL, TimeTilDormant, and TimeTilDormantAutoDelete are enterprise features.
UseRestartRequirement: false,
MaxTTL: 0,
RestartRequirement: TemplateRestartRequirement{
UseAutostopRequirement: false,
MaxTTL: 0,
AutostopRequirement: TemplateAutostopRequirement{
DaysOfWeek: 0,
Weeks: 0,
},
@ -180,14 +180,14 @@ func (*agplTemplateScheduleStore) Set(ctx context.Context, db database.Store, tp
DefaultTTL: int64(opts.DefaultTTL),
// Don't allow changing these settings, but keep the value in the DB (to
// avoid clearing settings if the license has an issue).
MaxTTL: tpl.MaxTTL,
RestartRequirementDaysOfWeek: tpl.RestartRequirementDaysOfWeek,
RestartRequirementWeeks: tpl.RestartRequirementWeeks,
AllowUserAutostart: tpl.AllowUserAutostart,
AllowUserAutostop: tpl.AllowUserAutostop,
FailureTTL: tpl.FailureTTL,
TimeTilDormant: tpl.TimeTilDormant,
TimeTilDormantAutoDelete: tpl.TimeTilDormantAutoDelete,
MaxTTL: tpl.MaxTTL,
AutostopRequirementDaysOfWeek: tpl.AutostopRequirementDaysOfWeek,
AutostopRequirementWeeks: tpl.AutostopRequirementWeeks,
AllowUserAutostart: tpl.AllowUserAutostart,
AllowUserAutostop: tpl.AllowUserAutostop,
FailureTTL: tpl.FailureTTL,
TimeTilDormant: tpl.TimeTilDormant,
TimeTilDormantAutoDelete: tpl.TimeTilDormantAutoDelete,
})
if err != nil {
return xerrors.Errorf("update template schedule: %w", err)

View File

@ -214,20 +214,20 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
var (
defaultTTL time.Duration
// TODO(@dean): remove max_ttl once restart_requirement is ready
maxTTL time.Duration
restartRequirementDaysOfWeek []string
restartRequirementWeeks int64
failureTTL time.Duration
dormantTTL time.Duration
dormantAutoDeletionTTL time.Duration
// TODO(@dean): remove max_ttl once autostop_requirement is ready
maxTTL time.Duration
autostopRequirementDaysOfWeek []string
autostopRequirementWeeks int64
failureTTL time.Duration
dormantTTL time.Duration
dormantAutoDeletionTTL time.Duration
)
if createTemplate.DefaultTTLMillis != nil {
defaultTTL = time.Duration(*createTemplate.DefaultTTLMillis) * time.Millisecond
}
if createTemplate.RestartRequirement != nil {
restartRequirementDaysOfWeek = createTemplate.RestartRequirement.DaysOfWeek
restartRequirementWeeks = createTemplate.RestartRequirement.Weeks
if createTemplate.AutostopRequirement != nil {
autostopRequirementDaysOfWeek = createTemplate.AutostopRequirement.DaysOfWeek
autostopRequirementWeeks = createTemplate.AutostopRequirement.Weeks
}
if createTemplate.FailureTTLMillis != nil {
failureTTL = time.Duration(*createTemplate.FailureTTLMillis) * time.Millisecond
@ -240,8 +240,8 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
}
var (
validErrs []codersdk.ValidationError
restartRequirementDaysOfWeekParsed uint8
validErrs []codersdk.ValidationError
autostopRequirementDaysOfWeekParsed uint8
)
if defaultTTL < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
@ -252,20 +252,20 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
if maxTTL != 0 && defaultTTL > maxTTL {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be less than or equal to max_ttl_ms if max_ttl_ms is set."})
}
if len(restartRequirementDaysOfWeek) > 0 {
restartRequirementDaysOfWeekParsed, err = codersdk.WeekdaysToBitmap(restartRequirementDaysOfWeek)
if len(autostopRequirementDaysOfWeek) > 0 {
autostopRequirementDaysOfWeekParsed, err = codersdk.WeekdaysToBitmap(autostopRequirementDaysOfWeek)
if err != nil {
validErrs = append(validErrs, codersdk.ValidationError{Field: "restart_requirement.days_of_week", Detail: err.Error()})
validErrs = append(validErrs, codersdk.ValidationError{Field: "autostop_requirement.days_of_week", Detail: err.Error()})
}
}
if createTemplate.MaxTTLMillis != nil {
maxTTL = time.Duration(*createTemplate.MaxTTLMillis) * time.Millisecond
}
if restartRequirementWeeks < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "restart_requirement.weeks", Detail: "Must be a positive integer."})
if autostopRequirementWeeks < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "autostop_requirement.weeks", Detail: "Must be a positive integer."})
}
if restartRequirementWeeks > schedule.MaxTemplateRestartRequirementWeeks {
validErrs = append(validErrs, codersdk.ValidationError{Field: "restart_requirement.weeks", Detail: fmt.Sprintf("Must be less than %d.", schedule.MaxTemplateRestartRequirementWeeks)})
if autostopRequirementWeeks > schedule.MaxTemplateAutostopRequirementWeeks {
validErrs = append(validErrs, codersdk.ValidationError{Field: "autostop_requirement.weeks", Detail: fmt.Sprintf("Must be less than %d.", schedule.MaxTemplateAutostopRequirementWeeks)})
}
if failureTTL < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "failure_ttl_ms", Detail: "Must be a positive integer."})
@ -336,9 +336,9 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
// Some of these values are enterprise-only, but the
// TemplateScheduleStore will handle avoiding setting them if
// unlicensed.
RestartRequirement: schedule.TemplateRestartRequirement{
DaysOfWeek: restartRequirementDaysOfWeekParsed,
Weeks: restartRequirementWeeks,
AutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: autostopRequirementDaysOfWeekParsed,
Weeks: autostopRequirementWeeks,
},
FailureTTL: failureTTL,
TimeTilDormant: dormantTTL,
@ -500,8 +500,8 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
}
var (
validErrs []codersdk.ValidationError
restartRequirementDaysOfWeekParsed uint8
validErrs []codersdk.ValidationError
autostopRequirementDaysOfWeekParsed uint8
)
if req.DefaultTTLMillis < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be a positive integer."})
@ -512,23 +512,23 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
if req.MaxTTLMillis != 0 && req.DefaultTTLMillis > req.MaxTTLMillis {
validErrs = append(validErrs, codersdk.ValidationError{Field: "default_ttl_ms", Detail: "Must be less than or equal to max_ttl_ms if max_ttl_ms is set."})
}
if req.RestartRequirement == nil {
req.RestartRequirement = &codersdk.TemplateRestartRequirement{
DaysOfWeek: codersdk.BitmapToWeekdays(scheduleOpts.RestartRequirement.DaysOfWeek),
Weeks: scheduleOpts.RestartRequirement.Weeks,
if req.AutostopRequirement == nil {
req.AutostopRequirement = &codersdk.TemplateAutostopRequirement{
DaysOfWeek: codersdk.BitmapToWeekdays(scheduleOpts.AutostopRequirement.DaysOfWeek),
Weeks: scheduleOpts.AutostopRequirement.Weeks,
}
}
if len(req.RestartRequirement.DaysOfWeek) > 0 {
restartRequirementDaysOfWeekParsed, err = codersdk.WeekdaysToBitmap(req.RestartRequirement.DaysOfWeek)
if len(req.AutostopRequirement.DaysOfWeek) > 0 {
autostopRequirementDaysOfWeekParsed, err = codersdk.WeekdaysToBitmap(req.AutostopRequirement.DaysOfWeek)
if err != nil {
validErrs = append(validErrs, codersdk.ValidationError{Field: "restart_requirement.days_of_week", Detail: err.Error()})
validErrs = append(validErrs, codersdk.ValidationError{Field: "autostop_requirement.days_of_week", Detail: err.Error()})
}
}
if req.RestartRequirement.Weeks < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "restart_requirement.weeks", Detail: "Must be a positive integer."})
if req.AutostopRequirement.Weeks < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "autostop_requirement.weeks", Detail: "Must be a positive integer."})
}
if req.RestartRequirement.Weeks > schedule.MaxTemplateRestartRequirementWeeks {
validErrs = append(validErrs, codersdk.ValidationError{Field: "restart_requirement.weeks", Detail: fmt.Sprintf("Must be less than %d.", schedule.MaxTemplateRestartRequirementWeeks)})
if req.AutostopRequirement.Weeks > schedule.MaxTemplateAutostopRequirementWeeks {
validErrs = append(validErrs, codersdk.ValidationError{Field: "autostop_requirement.weeks", Detail: fmt.Sprintf("Must be less than %d.", schedule.MaxTemplateAutostopRequirementWeeks)})
}
if req.FailureTTLMillis < 0 {
validErrs = append(validErrs, codersdk.ValidationError{Field: "failure_ttl_ms", Detail: "Must be a positive integer."})
@ -562,8 +562,8 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
req.AllowUserCancelWorkspaceJobs == template.AllowUserCancelWorkspaceJobs &&
req.DefaultTTLMillis == time.Duration(template.DefaultTTL).Milliseconds() &&
req.MaxTTLMillis == time.Duration(template.MaxTTL).Milliseconds() &&
restartRequirementDaysOfWeekParsed == scheduleOpts.RestartRequirement.DaysOfWeek &&
req.RestartRequirement.Weeks == scheduleOpts.RestartRequirement.Weeks &&
autostopRequirementDaysOfWeekParsed == scheduleOpts.AutostopRequirement.DaysOfWeek &&
req.AutostopRequirement.Weeks == scheduleOpts.AutostopRequirement.Weeks &&
req.FailureTTLMillis == time.Duration(template.FailureTTL).Milliseconds() &&
req.TimeTilDormantMillis == time.Duration(template.TimeTilDormant).Milliseconds() &&
req.TimeTilDormantAutoDeleteMillis == time.Duration(template.TimeTilDormantAutoDelete).Milliseconds() {
@ -603,8 +603,8 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
if defaultTTL != time.Duration(template.DefaultTTL) ||
maxTTL != time.Duration(template.MaxTTL) ||
restartRequirementDaysOfWeekParsed != scheduleOpts.RestartRequirement.DaysOfWeek ||
req.RestartRequirement.Weeks != scheduleOpts.RestartRequirement.Weeks ||
autostopRequirementDaysOfWeekParsed != scheduleOpts.AutostopRequirement.DaysOfWeek ||
req.AutostopRequirement.Weeks != scheduleOpts.AutostopRequirement.Weeks ||
failureTTL != time.Duration(template.FailureTTL) ||
inactivityTTL != time.Duration(template.TimeTilDormant) ||
timeTilDormantAutoDelete != time.Duration(template.TimeTilDormantAutoDelete) ||
@ -618,9 +618,9 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
UserAutostopEnabled: req.AllowUserAutostop,
DefaultTTL: defaultTTL,
MaxTTL: maxTTL,
RestartRequirement: schedule.TemplateRestartRequirement{
DaysOfWeek: restartRequirementDaysOfWeekParsed,
Weeks: req.RestartRequirement.Weeks,
AutostopRequirement: schedule.TemplateAutostopRequirement{
DaysOfWeek: autostopRequirementDaysOfWeekParsed,
Weeks: req.AutostopRequirement.Weeks,
},
FailureTTL: failureTTL,
TimeTilDormant: inactivityTTL,
@ -760,9 +760,9 @@ func (api *API) convertTemplate(
FailureTTLMillis: time.Duration(template.FailureTTL).Milliseconds(),
TimeTilDormantMillis: time.Duration(template.TimeTilDormant).Milliseconds(),
TimeTilDormantAutoDeleteMillis: time.Duration(template.TimeTilDormantAutoDelete).Milliseconds(),
RestartRequirement: codersdk.TemplateRestartRequirement{
DaysOfWeek: codersdk.BitmapToWeekdays(uint8(template.RestartRequirementDaysOfWeek)),
Weeks: template.RestartRequirementWeeks,
AutostopRequirement: codersdk.TemplateAutostopRequirement{
DaysOfWeek: codersdk.BitmapToWeekdays(uint8(template.AutostopRequirementDaysOfWeek)),
Weeks: template.AutostopRequirementWeeks,
},
}
}

View File

@ -246,7 +246,7 @@ func TestPostTemplateByOrganization(t *testing.T) {
require.Equal(t, http.StatusNotFound, apiErr.StatusCode())
})
t.Run("RestartRequirement", func(t *testing.T) {
t.Run("AutostopRequirement", func(t *testing.T) {
t.Parallel()
t.Run("None", func(t *testing.T) {
@ -257,21 +257,21 @@ func TestPostTemplateByOrganization(t *testing.T) {
TemplateScheduleStore: schedule.MockTemplateScheduleStore{
SetFn: func(ctx context.Context, db database.Store, template database.Template, options schedule.TemplateScheduleOptions) (database.Template, error) {
atomic.AddInt64(&setCalled, 1)
assert.Zero(t, options.RestartRequirement.DaysOfWeek)
assert.Zero(t, options.RestartRequirement.Weeks)
assert.Zero(t, options.AutostopRequirement.DaysOfWeek)
assert.Zero(t, options.AutostopRequirement.Weeks)
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
RestartRequirementDaysOfWeek: int16(options.RestartRequirement.DaysOfWeek),
RestartRequirementWeeks: options.RestartRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: options.AutostopRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
})
if !assert.NoError(t, err) {
return database.Template{}, err
@ -288,15 +288,15 @@ func TestPostTemplateByOrganization(t *testing.T) {
defer cancel()
got, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{
Name: "testing",
VersionID: version.ID,
RestartRequirement: nil,
Name: "testing",
VersionID: version.ID,
AutostopRequirement: nil,
})
require.NoError(t, err)
require.EqualValues(t, 1, atomic.LoadInt64(&setCalled))
require.Empty(t, got.RestartRequirement.DaysOfWeek)
require.Zero(t, got.RestartRequirement.Weeks)
require.Empty(t, got.AutostopRequirement.DaysOfWeek)
require.Zero(t, got.AutostopRequirement.Weeks)
})
t.Run("OK", func(t *testing.T) {
@ -307,21 +307,21 @@ func TestPostTemplateByOrganization(t *testing.T) {
TemplateScheduleStore: schedule.MockTemplateScheduleStore{
SetFn: func(ctx context.Context, db database.Store, template database.Template, options schedule.TemplateScheduleOptions) (database.Template, error) {
atomic.AddInt64(&setCalled, 1)
assert.EqualValues(t, 0b00110000, options.RestartRequirement.DaysOfWeek)
assert.EqualValues(t, 2, options.RestartRequirement.Weeks)
assert.EqualValues(t, 0b00110000, options.AutostopRequirement.DaysOfWeek)
assert.EqualValues(t, 2, options.AutostopRequirement.Weeks)
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
RestartRequirementDaysOfWeek: int16(options.RestartRequirement.DaysOfWeek),
RestartRequirementWeeks: options.RestartRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: options.AutostopRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
})
if !assert.NoError(t, err) {
return database.Template{}, err
@ -340,7 +340,7 @@ func TestPostTemplateByOrganization(t *testing.T) {
got, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{
Name: "testing",
VersionID: version.ID,
RestartRequirement: &codersdk.TemplateRestartRequirement{
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
// wrong order
DaysOfWeek: []string{"saturday", "friday"},
Weeks: 2,
@ -349,13 +349,13 @@ func TestPostTemplateByOrganization(t *testing.T) {
require.NoError(t, err)
require.EqualValues(t, 1, atomic.LoadInt64(&setCalled))
require.Equal(t, []string{"friday", "saturday"}, got.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 2, got.RestartRequirement.Weeks)
require.Equal(t, []string{"friday", "saturday"}, got.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 2, got.AutostopRequirement.Weeks)
got, err = client.Template(ctx, got.ID)
require.NoError(t, err)
require.Equal(t, []string{"friday", "saturday"}, got.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 2, got.RestartRequirement.Weeks)
require.Equal(t, []string{"friday", "saturday"}, got.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 2, got.AutostopRequirement.Weeks)
})
t.Run("IgnoredUnlicensed", func(t *testing.T) {
@ -371,15 +371,15 @@ func TestPostTemplateByOrganization(t *testing.T) {
got, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{
Name: "testing",
VersionID: version.ID,
RestartRequirement: &codersdk.TemplateRestartRequirement{
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
DaysOfWeek: []string{"friday", "saturday"},
Weeks: 2,
},
})
require.NoError(t, err)
// ignored and use AGPL defaults
require.Empty(t, got.RestartRequirement.DaysOfWeek)
require.Zero(t, got.RestartRequirement.Weeks)
require.Empty(t, got.AutostopRequirement.DaysOfWeek)
require.Zero(t, got.AutostopRequirement.Weeks)
})
})
}
@ -589,17 +589,17 @@ func TestPatchTemplateMeta(t *testing.T) {
}
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
RestartRequirementDaysOfWeek: int16(options.RestartRequirement.DaysOfWeek),
RestartRequirementWeeks: options.RestartRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: options.AutostopRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
})
if !assert.NoError(t, err) {
return database.Template{}, err
@ -738,7 +738,7 @@ func TestPatchTemplateMeta(t *testing.T) {
Description: template.Description,
Icon: template.Icon,
DefaultTTLMillis: 0,
RestartRequirement: &template.RestartRequirement,
AutostopRequirement: &template.AutostopRequirement,
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
FailureTTLMillis: failureTTL.Milliseconds(),
TimeTilDormantMillis: inactivityTTL.Milliseconds(),
@ -773,7 +773,7 @@ func TestPatchTemplateMeta(t *testing.T) {
Description: template.Description,
Icon: template.Icon,
DefaultTTLMillis: template.DefaultTTLMillis,
RestartRequirement: &template.RestartRequirement,
AutostopRequirement: &template.AutostopRequirement,
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
FailureTTLMillis: failureTTL.Milliseconds(),
TimeTilDormantMillis: inactivityTTL.Milliseconds(),
@ -832,7 +832,7 @@ func TestPatchTemplateMeta(t *testing.T) {
Description: template.Description,
Icon: template.Icon,
DefaultTTLMillis: template.DefaultTTLMillis,
RestartRequirement: &template.RestartRequirement,
AutostopRequirement: &template.AutostopRequirement,
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
AllowUserAutostart: allowAutostart.Load(),
AllowUserAutostop: allowAutostop.Load(),
@ -864,7 +864,7 @@ func TestPatchTemplateMeta(t *testing.T) {
Icon: template.Icon,
// Increase the default TTL to avoid error "not modified".
DefaultTTLMillis: template.DefaultTTLMillis + 1,
RestartRequirement: &template.RestartRequirement,
AutostopRequirement: &template.AutostopRequirement,
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
AllowUserAutostart: false,
AllowUserAutostop: false,
@ -891,13 +891,13 @@ func TestPatchTemplateMeta(t *testing.T) {
defer cancel()
req := codersdk.UpdateTemplateMeta{
Name: template.Name,
Description: template.Description,
Icon: template.Icon,
DefaultTTLMillis: template.DefaultTTLMillis,
RestartRequirement: nil,
AllowUserAutostart: template.AllowUserAutostart,
AllowUserAutostop: template.AllowUserAutostop,
Name: template.Name,
Description: template.Description,
Icon: template.Icon,
DefaultTTLMillis: template.DefaultTTLMillis,
AutostopRequirement: nil,
AllowUserAutostart: template.AllowUserAutostart,
AllowUserAutostop: template.AllowUserAutostop,
}
_, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.ErrorContains(t, err, "not modified")
@ -964,7 +964,7 @@ func TestPatchTemplateMeta(t *testing.T) {
assert.Equal(t, updated.Icon, "")
})
t.Run("RestartRequirement", func(t *testing.T) {
t.Run("AutostopRequirement", func(t *testing.T) {
t.Parallel()
t.Run("OK", func(t *testing.T) {
@ -975,22 +975,22 @@ func TestPatchTemplateMeta(t *testing.T) {
TemplateScheduleStore: schedule.MockTemplateScheduleStore{
SetFn: func(ctx context.Context, db database.Store, template database.Template, options schedule.TemplateScheduleOptions) (database.Template, error) {
if atomic.AddInt64(&setCalled, 1) == 2 {
assert.EqualValues(t, 0b0110000, options.RestartRequirement.DaysOfWeek)
assert.EqualValues(t, 2, options.RestartRequirement.Weeks)
assert.EqualValues(t, 0b0110000, options.AutostopRequirement.DaysOfWeek)
assert.EqualValues(t, 2, options.AutostopRequirement.Weeks)
}
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
RestartRequirementDaysOfWeek: int16(options.RestartRequirement.DaysOfWeek),
RestartRequirementWeeks: options.RestartRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: options.AutostopRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
})
if !assert.NoError(t, err) {
return database.Template{}, err
@ -1005,8 +1005,8 @@ func TestPatchTemplateMeta(t *testing.T) {
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
require.EqualValues(t, 1, atomic.LoadInt64(&setCalled))
require.Empty(t, template.RestartRequirement.DaysOfWeek)
require.Zero(t, template.RestartRequirement.Weeks)
require.Empty(t, template.AutostopRequirement.DaysOfWeek)
require.Zero(t, template.AutostopRequirement.Weeks)
req := codersdk.UpdateTemplateMeta{
Name: template.Name,
DisplayName: template.DisplayName,
@ -1014,7 +1014,7 @@ func TestPatchTemplateMeta(t *testing.T) {
Icon: template.Icon,
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
DefaultTTLMillis: time.Hour.Milliseconds(),
RestartRequirement: &codersdk.TemplateRestartRequirement{
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
// wrong order
DaysOfWeek: []string{"saturday", "friday"},
Weeks: 2,
@ -1027,13 +1027,13 @@ func TestPatchTemplateMeta(t *testing.T) {
updated, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)
require.EqualValues(t, 2, atomic.LoadInt64(&setCalled))
require.Equal(t, []string{"friday", "saturday"}, updated.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 2, updated.RestartRequirement.Weeks)
require.Equal(t, []string{"friday", "saturday"}, updated.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 2, updated.AutostopRequirement.Weeks)
template, err = client.Template(ctx, template.ID)
require.NoError(t, err)
require.Equal(t, []string{"friday", "saturday"}, template.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 2, template.RestartRequirement.Weeks)
require.Equal(t, []string{"friday", "saturday"}, template.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 2, template.AutostopRequirement.Weeks)
})
t.Run("Unset", func(t *testing.T) {
@ -1044,22 +1044,22 @@ func TestPatchTemplateMeta(t *testing.T) {
TemplateScheduleStore: schedule.MockTemplateScheduleStore{
SetFn: func(ctx context.Context, db database.Store, template database.Template, options schedule.TemplateScheduleOptions) (database.Template, error) {
if atomic.AddInt64(&setCalled, 1) == 2 {
assert.EqualValues(t, 0, options.RestartRequirement.DaysOfWeek)
assert.EqualValues(t, 0, options.RestartRequirement.Weeks)
assert.EqualValues(t, 0, options.AutostopRequirement.DaysOfWeek)
assert.EqualValues(t, 0, options.AutostopRequirement.Weeks)
}
err := db.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
RestartRequirementDaysOfWeek: int16(options.RestartRequirement.DaysOfWeek),
RestartRequirementWeeks: options.RestartRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
ID: template.ID,
UpdatedAt: database.Now(),
AllowUserAutostart: options.UserAutostartEnabled,
AllowUserAutostop: options.UserAutostopEnabled,
DefaultTTL: int64(options.DefaultTTL),
MaxTTL: int64(options.MaxTTL),
AutostopRequirementDaysOfWeek: int16(options.AutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: options.AutostopRequirement.Weeks,
FailureTTL: int64(options.FailureTTL),
TimeTilDormant: int64(options.TimeTilDormant),
TimeTilDormantAutoDelete: int64(options.TimeTilDormantAutoDelete),
})
if !assert.NoError(t, err) {
return database.Template{}, err
@ -1073,15 +1073,15 @@ func TestPatchTemplateMeta(t *testing.T) {
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
ctr.RestartRequirement = &codersdk.TemplateRestartRequirement{
ctr.AutostopRequirement = &codersdk.TemplateAutostopRequirement{
// wrong order
DaysOfWeek: []string{"sunday", "saturday", "friday", "thursday", "wednesday", "tuesday", "monday"},
Weeks: 2,
}
})
require.EqualValues(t, 1, atomic.LoadInt64(&setCalled))
require.Equal(t, []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}, template.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 2, template.RestartRequirement.Weeks)
require.Equal(t, []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}, template.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 2, template.AutostopRequirement.Weeks)
req := codersdk.UpdateTemplateMeta{
Name: template.Name,
DisplayName: template.DisplayName,
@ -1089,7 +1089,7 @@ func TestPatchTemplateMeta(t *testing.T) {
Icon: template.Icon,
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
DefaultTTLMillis: time.Hour.Milliseconds(),
RestartRequirement: &codersdk.TemplateRestartRequirement{
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
DaysOfWeek: []string{},
Weeks: 0,
},
@ -1101,13 +1101,13 @@ func TestPatchTemplateMeta(t *testing.T) {
updated, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)
require.EqualValues(t, 2, atomic.LoadInt64(&setCalled))
require.Empty(t, updated.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 0, updated.RestartRequirement.Weeks)
require.Empty(t, updated.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 0, updated.AutostopRequirement.Weeks)
template, err = client.Template(ctx, template.ID)
require.NoError(t, err)
require.Empty(t, template.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 0, template.RestartRequirement.Weeks)
require.Empty(t, template.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 0, template.AutostopRequirement.Weeks)
})
t.Run("EnterpriseOnly", func(t *testing.T) {
@ -1117,8 +1117,8 @@ func TestPatchTemplateMeta(t *testing.T) {
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
require.Empty(t, template.RestartRequirement.DaysOfWeek)
require.Zero(t, template.RestartRequirement.Weeks)
require.Empty(t, template.AutostopRequirement.DaysOfWeek)
require.Zero(t, template.AutostopRequirement.Weeks)
req := codersdk.UpdateTemplateMeta{
Name: template.Name,
DisplayName: template.DisplayName,
@ -1126,7 +1126,7 @@ func TestPatchTemplateMeta(t *testing.T) {
Icon: template.Icon,
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
DefaultTTLMillis: time.Hour.Milliseconds(),
RestartRequirement: &codersdk.TemplateRestartRequirement{
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
DaysOfWeek: []string{"monday"},
Weeks: 2,
},
@ -1137,13 +1137,13 @@ func TestPatchTemplateMeta(t *testing.T) {
updated, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)
require.Empty(t, updated.RestartRequirement.DaysOfWeek)
require.Zero(t, updated.RestartRequirement.Weeks)
require.Empty(t, updated.AutostopRequirement.DaysOfWeek)
require.Zero(t, updated.AutostopRequirement.Weeks)
template, err = client.Template(ctx, template.ID)
require.NoError(t, err)
require.Empty(t, template.RestartRequirement.DaysOfWeek)
require.Zero(t, template.RestartRequirement.Weeks)
require.Empty(t, template.AutostopRequirement.DaysOfWeek)
require.Zero(t, template.AutostopRequirement.Weeks)
})
})
}

View File

@ -384,8 +384,8 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
}
maxTTL := templateSchedule.MaxTTL
if templateSchedule.UseRestartRequirement {
// If we're using restart requirements, there isn't a max TTL.
if templateSchedule.UseAutostopRequirement {
// If we're using autostop requirements, there isn't a max TTL.
maxTTL = 0
}
@ -721,8 +721,8 @@ func (api *API) putWorkspaceTTL(rw http.ResponseWriter, r *http.Request) {
}
maxTTL := templateSchedule.MaxTTL
if templateSchedule.UseRestartRequirement {
// If we're using restart requirements, there isn't a max TTL.
if templateSchedule.UseAutostopRequirement {
// If we're using autostop requirements, there isn't a max TTL.
maxTTL = 0
}

View File

@ -1839,7 +1839,7 @@ func TestWorkspaceUpdateAutostart(t *testing.T) {
UserAutostartEnabled: false,
UserAutostopEnabled: false,
DefaultTTL: 0,
RestartRequirement: schedule.TemplateRestartRequirement{},
AutostopRequirement: schedule.TemplateAutostopRequirement{},
}, nil
},
SetFn: func(_ context.Context, _ database.Store, tpl database.Template, _ schedule.TemplateScheduleOptions) (database.Template, error) {
@ -2006,7 +2006,7 @@ func TestWorkspaceUpdateTTL(t *testing.T) {
UserAutostartEnabled: false,
UserAutostopEnabled: false,
DefaultTTL: 0,
RestartRequirement: schedule.TemplateRestartRequirement{},
AutostopRequirement: schedule.TemplateAutostopRequirement{},
}, nil
},
SetFn: func(_ context.Context, _ database.Store, tpl database.Template, _ schedule.TemplateScheduleOptions) (database.Template, error) {

View File

@ -35,19 +35,19 @@ const (
type FeatureName string
const (
FeatureUserLimit FeatureName = "user_limit"
FeatureAuditLog FeatureName = "audit_log"
FeatureBrowserOnly FeatureName = "browser_only"
FeatureSCIM FeatureName = "scim"
FeatureTemplateRBAC FeatureName = "template_rbac"
FeatureUserRoleManagement FeatureName = "user_role_management"
FeatureHighAvailability FeatureName = "high_availability"
FeatureMultipleGitAuth FeatureName = "multiple_git_auth"
FeatureExternalProvisionerDaemons FeatureName = "external_provisioner_daemons"
FeatureAppearance FeatureName = "appearance"
FeatureAdvancedTemplateScheduling FeatureName = "advanced_template_scheduling"
FeatureTemplateRestartRequirement FeatureName = "template_restart_requirement"
FeatureWorkspaceProxy FeatureName = "workspace_proxy"
FeatureUserLimit FeatureName = "user_limit"
FeatureAuditLog FeatureName = "audit_log"
FeatureBrowserOnly FeatureName = "browser_only"
FeatureSCIM FeatureName = "scim"
FeatureTemplateRBAC FeatureName = "template_rbac"
FeatureUserRoleManagement FeatureName = "user_role_management"
FeatureHighAvailability FeatureName = "high_availability"
FeatureMultipleGitAuth FeatureName = "multiple_git_auth"
FeatureExternalProvisionerDaemons FeatureName = "external_provisioner_daemons"
FeatureAppearance FeatureName = "appearance"
FeatureAdvancedTemplateScheduling FeatureName = "advanced_template_scheduling"
FeatureTemplateAutostopRequirement FeatureName = "template_autostop_requirement"
FeatureWorkspaceProxy FeatureName = "workspace_proxy"
)
// FeatureNames must be kept in-sync with the Feature enum above.
@ -1924,17 +1924,19 @@ const (
// WARNING: This cannot be enabled when using HA.
ExperimentSingleTailnet Experiment = "single_tailnet"
// ExperimentTemplateRestartRequirement allows template admins to have more
// ExperimentTemplateAutostopRequirement allows template admins to have more
// control over when workspaces created on a template are required to
// restart, and allows users to ensure these restarts never happen during
// their business hours.
// stop, and allows users to ensure these restarts never happen during their
// business hours.
//
// This will replace the MaxTTL setting on templates.
//
// Enables:
// - User quiet hours schedule settings
// - Template restart requirement settings
// - Changes the max_deadline algorithm to use restart requirement and user
// - Template autostop requirement settings
// - Changes the max_deadline algorithm to use autostop requirement and user
// quiet hours instead of max_ttl.
ExperimentTemplateRestartRequirement Experiment = "template_restart_requirement"
ExperimentTemplateAutostopRequirement Experiment = "template_autostop_requirement"
// Deployment health page
ExperimentDeploymentHealthPage Experiment = "deployment_health_page"

View File

@ -84,11 +84,11 @@ type CreateTemplateRequest struct {
// DefaultTTLMillis allows optionally specifying the default TTL
// for all workspaces created from this template.
DefaultTTLMillis *int64 `json:"default_ttl_ms,omitempty"`
// TODO(@dean): remove max_ttl once restart_requirement is matured
// TODO(@dean): remove max_ttl once autostop_requirement is matured
MaxTTLMillis *int64 `json:"max_ttl_ms,omitempty"`
// RestartRequirement allows optionally specifying the restart requirement
// AutostopRequirement allows optionally specifying the autostop requirement
// for workspaces created from this template. This is an enterprise feature.
RestartRequirement *TemplateRestartRequirement `json:"restart_requirement,omitempty"`
AutostopRequirement *TemplateAutostopRequirement `json:"autostop_requirement,omitempty"`
// Allow users to cancel in-progress workspace jobs.
// *bool as the default value is "true".

View File

@ -29,13 +29,13 @@ type Template struct {
Description string `json:"description"`
Icon string `json:"icon"`
DefaultTTLMillis int64 `json:"default_ttl_ms"`
// TODO(@dean): remove max_ttl once restart_requirement is matured
// TODO(@dean): remove max_ttl once autostop_requirement is matured
MaxTTLMillis int64 `json:"max_ttl_ms"`
// RestartRequirement is an enterprise feature. Its value is only used if
// AutostopRequirement is an enterprise feature. Its value is only used if
// your license is entitled to use the advanced template scheduling feature.
RestartRequirement TemplateRestartRequirement `json:"restart_requirement"`
CreatedByID uuid.UUID `json:"created_by_id" format:"uuid"`
CreatedByName string `json:"created_by_name"`
AutostopRequirement TemplateAutostopRequirement `json:"autostop_requirement"`
CreatedByID uuid.UUID `json:"created_by_id" format:"uuid"`
CreatedByName string `json:"created_by_name"`
// AllowUserAutostart and AllowUserAutostop are enterprise-only. Their
// values are only used if your license is entitled to use the advanced
@ -107,7 +107,7 @@ func BitmapToWeekdays(bitmap uint8) []string {
return days
}
type TemplateRestartRequirement struct {
type TemplateAutostopRequirement struct {
// DaysOfWeek is a list of days of the week on which restarts are required.
// Restarts happen within the user's quiet hours (in their configured
// timezone). If no days are specified, restarts are not required. Weekdays
@ -180,18 +180,18 @@ type UpdateTemplateMeta struct {
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
DefaultTTLMillis int64 `json:"default_ttl_ms,omitempty"`
// TODO(@dean): remove max_ttl once restart_requirement is matured
// TODO(@dean): remove max_ttl once autostop_requirement is matured
MaxTTLMillis int64 `json:"max_ttl_ms,omitempty"`
// RestartRequirement can only be set if your license includes the advanced
// AutostopRequirement can only be set if your license includes the advanced
// template scheduling feature. If you attempt to set this value while
// unlicensed, it will be ignored.
RestartRequirement *TemplateRestartRequirement `json:"restart_requirement,omitempty"`
AllowUserAutostart bool `json:"allow_user_autostart,omitempty"`
AllowUserAutostop bool `json:"allow_user_autostop,omitempty"`
AllowUserCancelWorkspaceJobs bool `json:"allow_user_cancel_workspace_jobs,omitempty"`
FailureTTLMillis int64 `json:"failure_ttl_ms,omitempty"`
TimeTilDormantMillis int64 `json:"time_til_dormant_ms,omitempty"`
TimeTilDormantAutoDeleteMillis int64 `json:"time_til_dormant_autodelete_ms,omitempty"`
AutostopRequirement *TemplateAutostopRequirement `json:"autostop_requirement,omitempty"`
AllowUserAutostart bool `json:"allow_user_autostart,omitempty"`
AllowUserAutostop bool `json:"allow_user_autostop,omitempty"`
AllowUserCancelWorkspaceJobs bool `json:"allow_user_cancel_workspace_jobs,omitempty"`
FailureTTLMillis int64 `json:"failure_ttl_ms,omitempty"`
TimeTilDormantMillis int64 `json:"time_til_dormant_ms,omitempty"`
TimeTilDormantAutoDeleteMillis int64 `json:"time_til_dormant_autodelete_ms,omitempty"`
// UpdateWorkspaceLastUsedAt updates the last_used_at field of workspaces
// spawned from the template. This is useful for preventing workspaces being
// immediately locked when updating the inactivity_ttl field to a new, shorter

View File

@ -8,19 +8,19 @@ 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> |
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
| 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>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_ttl</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>restart_requirement_days_of_week</td><td>true</td></tr><tr><td>restart_requirement_weeks</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>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>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</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>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>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>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>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> |
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
| 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>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_ttl</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>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>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</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>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>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>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
<!-- End generated by 'make docs/admin/audit-logs.md'. -->

152
docs/api/schemas.md generated
View File

@ -1478,6 +1478,10 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
"allow_user_autostart": true,
"allow_user_autostop": true,
"allow_user_cancel_workspace_jobs": true,
"autostop_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"default_ttl_ms": 0,
"delete_ttl_ms": 0,
"description": "string",
@ -1488,33 +1492,29 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
"icon": "string",
"max_ttl_ms": 0,
"name": "string",
"restart_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `allow_user_autostart` | boolean | false | | Allow user autostart allows users to set a schedule for autostarting their workspace. By default this is true. This can only be disabled when using an enterprise license. |
| `allow_user_autostop` | boolean | false | | Allow user autostop allows users to set a custom workspace TTL to use in place of the template's DefaultTTL field. By default this is true. If false, the DefaultTTL will always be used. This can only be disabled when using an enterprise license. |
| `allow_user_cancel_workspace_jobs` | boolean | false | | Allow users to cancel in-progress workspace jobs. \*bool as the default value is "true". |
| `default_ttl_ms` | integer | false | | Default ttl ms allows optionally specifying the default TTL for all workspaces created from this template. |
| `delete_ttl_ms` | integer | false | | Delete ttl ms allows optionally specifying the max lifetime before Coder permanently deletes dormant workspaces created from this template. |
| `description` | string | false | | Description is a description of what the template contains. It must be less than 128 bytes. |
| `disable_everyone_group_access` | boolean | false | | Disable everyone group access allows optionally disabling the default behavior of granting the 'everyone' group access to use the template. If this is set to true, the template will not be available to all users, and must be explicitly granted to users or groups in the permissions settings of the template. |
| `display_name` | string | false | | Display name is the displayed name of the template. |
| `dormant_ttl_ms` | integer | false | | Dormant ttl ms allows optionally specifying the max lifetime before Coder locks inactive workspaces created from this 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. |
| `max_ttl_ms` | integer | false | | Max ttl ms remove max_ttl once restart_requirement is matured |
| `name` | string | true | | Name is the name of the template. |
| `restart_requirement` | [codersdk.TemplateRestartRequirement](#codersdktemplaterestartrequirement) | false | | Restart requirement allows optionally specifying the restart requirement for workspaces created from this template. This is an enterprise feature. |
| `template_version_id` | string | true | | Template version ID is an in-progress or completed job to use as an initial version of the template. |
| Name | Type | Required | Restrictions | Description |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `allow_user_autostart` | boolean | false | | Allow user autostart allows users to set a schedule for autostarting their workspace. By default this is true. This can only be disabled when using an enterprise license. |
| `allow_user_autostop` | boolean | false | | Allow user autostop allows users to set a custom workspace TTL to use in place of the template's DefaultTTL field. By default this is true. If false, the DefaultTTL will always be used. This can only be disabled when using an enterprise license. |
| `allow_user_cancel_workspace_jobs` | boolean | false | | Allow users to cancel in-progress workspace jobs. \*bool as the default value is "true". |
| `autostop_requirement` | [codersdk.TemplateAutostopRequirement](#codersdktemplateautostoprequirement) | false | | Autostop requirement allows optionally specifying the autostop requirement for workspaces created from this template. This is an enterprise feature. |
| `default_ttl_ms` | integer | false | | Default ttl ms allows optionally specifying the default TTL for all workspaces created from this template. |
| `delete_ttl_ms` | integer | false | | Delete ttl ms allows optionally specifying the max lifetime before Coder permanently deletes dormant workspaces created from this template. |
| `description` | string | false | | Description is a description of what the template contains. It must be less than 128 bytes. |
| `disable_everyone_group_access` | boolean | false | | Disable everyone group access allows optionally disabling the default behavior of granting the 'everyone' group access to use the template. If this is set to true, the template will not be available to all users, and must be explicitly granted to users or groups in the permissions settings of the template. |
| `display_name` | string | false | | Display name is the displayed name of the template. |
| `dormant_ttl_ms` | integer | false | | Dormant ttl ms allows optionally specifying the max lifetime before Coder locks inactive workspaces created from this 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. |
| `max_ttl_ms` | integer | false | | Max ttl ms remove max_ttl once autostop_requirement is matured |
| `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. |
| This is required on creation to enable a user-flow of validating a template works. There is no reason the data-model cannot support empty templates, but it doesn't make sense for users. |
## codersdk.CreateTemplateVersionDryRunRequest
@ -2711,15 +2711,15 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
#### Enumerated Values
| Value |
| ------------------------------ |
| `moons` |
| `workspace_actions` |
| `tailnet_pg_coordinator` |
| `single_tailnet` |
| `template_restart_requirement` |
| `deployment_health_page` |
| `workspaces_batch_actions` |
| Value |
| ------------------------------- |
| `moons` |
| `workspace_actions` |
| `tailnet_pg_coordinator` |
| `single_tailnet` |
| `template_autostop_requirement` |
| `deployment_health_page` |
| `workspaces_batch_actions` |
## codersdk.Feature
@ -4220,6 +4220,10 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
"allow_user_autostart": true,
"allow_user_autostop": true,
"allow_user_cancel_workspace_jobs": true,
"autostop_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"build_time_stats": {
"property1": {
"p50": 123,
@ -4243,10 +4247,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"provisioner": "terraform",
"restart_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"time_til_dormant_autodelete_ms": 0,
"time_til_dormant_ms": 0,
"updated_at": "2019-08-24T14:15:22Z"
@ -4255,31 +4255,31 @@ 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 TimeTilDormantMillis, and TimeTilDormantAutoDeleteMillis 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 | | |
| `max_ttl_ms` | integer | false | | Max ttl ms remove max_ttl once restart_requirement is matured |
| `name` | string | false | | |
| `organization_id` | string | false | | |
| `provisioner` | string | false | | |
| `restart_requirement` | [codersdk.TemplateRestartRequirement](#codersdktemplaterestartrequirement) | false | | Restart requirement is an enterprise feature. Its value is only used if your license is entitled to use the advanced template scheduling feature. |
| `time_til_dormant_autodelete_ms` | integer | false | | |
| `time_til_dormant_ms` | integer | 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 | | |
| `autostop_requirement` | [codersdk.TemplateAutostopRequirement](#codersdktemplateautostoprequirement) | false | | Autostop requirement is an enterprise feature. Its value is only used if your license is entitled to use the advanced template scheduling feature. |
| `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 TimeTilDormantMillis, and TimeTilDormantAutoDeleteMillis 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 | | |
| `max_ttl_ms` | integer | false | | Max ttl ms remove max_ttl once autostop_requirement is matured |
| `name` | string | false | | |
| `organization_id` | string | false | | |
| `provisioner` | string | false | | |
| `time_til_dormant_autodelete_ms` | integer | false | | |
| `time_til_dormant_ms` | integer | false | | |
| `updated_at` | string | false | | |
#### Enumerated Values
@ -4326,6 +4326,23 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
| `builtin` |
| `app` |
## codersdk.TemplateAutostopRequirement
```json
{
"days_of_week": ["monday"],
"weeks": 0
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
| ------------------------------------------------------------------------------------- | --------------- | -------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `days_of_week` | array of string | false | | Days of week is a list of days of the week on which restarts are required. Restarts happen within the user's quiet hours (in their configured timezone). If no days are specified, restarts are not required. Weekdays cannot be specified twice. |
| Restarts will only happen on weekdays in this list on weeks which line up with Weeks. |
| `weeks` | integer | false | | Weeks is the number of weeks between required restarts. Weeks are synced across all workspaces (and Coder deployments) using modulo math on a hardcoded epoch week of January 2nd, 2023 (the first Monday of 2023). Values of 0 or 1 indicate weekly restarts. Values of 2 indicate fortnightly restarts, etc. |
## codersdk.TemplateBuildTimeStats
```json
@ -4566,23 +4583,6 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
| `count` | integer | false | | |
| `value` | string | false | | |
## codersdk.TemplateRestartRequirement
```json
{
"days_of_week": ["monday"],
"weeks": 0
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
| ------------------------------------------------------------------------------------- | --------------- | -------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `days_of_week` | array of string | false | | Days of week is a list of days of the week on which restarts are required. Restarts happen within the user's quiet hours (in their configured timezone). If no days are specified, restarts are not required. Weekdays cannot be specified twice. |
| Restarts will only happen on weekdays in this list on weeks which line up with Weeks. |
| `weeks` | integer | false | | Weeks is the number of weeks between required restarts. Weeks are synced across all workspaces (and Coder deployments) using modulo math on a hardcoded epoch week of January 2nd, 2023 (the first Monday of 2023). Values of 0 or 1 indicate weekly restarts. Values of 2 indicate fortnightly restarts, etc. |
## codersdk.TemplateRole
```json

110
docs/api/templates.md generated
View File

@ -31,6 +31,10 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"allow_user_autostart": true,
"allow_user_autostop": true,
"allow_user_cancel_workspace_jobs": true,
"autostop_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"build_time_stats": {
"property1": {
"p50": 123,
@ -54,10 +58,6 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"provisioner": "terraform",
"restart_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"time_til_dormant_autodelete_ms": 0,
"time_til_dormant_ms": 0,
"updated_at": "2019-08-24T14:15:22Z"
@ -75,38 +75,38 @@ 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 TimeTilDormantMillis, and TimeTilDormantAutoDeleteMillis 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 | | |
| `» max_ttl_ms` | integer | false | | Max ttl ms remove max_ttl once restart_requirement is matured |
| `» name` | string | false | | |
| `» organization_id` | string(uuid) | false | | |
| `» provisioner` | string | false | | |
| `» restart_requirement` | [codersdk.TemplateRestartRequirement](schemas.md#codersdktemplaterestartrequirement) | false | | Restart requirement is an enterprise feature. Its value is only used if your license is entitled to use the advanced template scheduling feature. |
| `»» days_of_week` | array | false | | »days of week is a list of days of the week on which restarts are required. Restarts happen within the user's quiet hours (in their configured timezone). If no days are specified, restarts are not required. Weekdays cannot be specified twice. |
| 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 | | |
| `» autostop_requirement` | [codersdk.TemplateAutostopRequirement](schemas.md#codersdktemplateautostoprequirement) | false | | Autostop requirement is an enterprise feature. Its value is only used if your license is entitled to use the advanced template scheduling feature. |
| `»» days_of_week` | array | false | | »days of week is a list of days of the week on which restarts are required. Restarts happen within the user's quiet hours (in their configured timezone). If no days are specified, restarts are not required. Weekdays cannot be specified twice. |
| Restarts will only happen on weekdays in this list on weeks which line up with Weeks. |
| `»» weeks` | integer | false | | Weeks is the number of weeks between required restarts. Weeks are synced across all workspaces (and Coder deployments) using modulo math on a hardcoded epoch week of January 2nd, 2023 (the first Monday of 2023). Values of 0 or 1 indicate weekly restarts. Values of 2 indicate fortnightly restarts, etc. |
| `» time_til_dormant_autodelete_ms` | integer | false | | |
| `» time_til_dormant_ms` | integer | false | | |
| `» updated_at` | string(date-time) | false | | |
| `»» weeks` | integer | false | | Weeks is the number of weeks between required restarts. Weeks are synced across all workspaces (and Coder deployments) using modulo math on a hardcoded epoch week of January 2nd, 2023 (the first Monday of 2023). Values of 0 or 1 indicate weekly restarts. Values of 2 indicate fortnightly restarts, etc. |
| `» 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 TimeTilDormantMillis, and TimeTilDormantAutoDeleteMillis 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 | | |
| `» max_ttl_ms` | integer | false | | Max ttl ms remove max_ttl once autostop_requirement is matured |
| `» name` | string | false | | |
| `» organization_id` | string(uuid) | false | | |
| `» provisioner` | string | false | | |
| `» time_til_dormant_autodelete_ms` | integer | false | | |
| `» time_til_dormant_ms` | integer | false | | |
| `» updated_at` | string(date-time) | false | | |
#### Enumerated Values
@ -137,6 +137,10 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
"allow_user_autostart": true,
"allow_user_autostop": true,
"allow_user_cancel_workspace_jobs": true,
"autostop_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"default_ttl_ms": 0,
"delete_ttl_ms": 0,
"description": "string",
@ -147,10 +151,6 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
"icon": "string",
"max_ttl_ms": 0,
"name": "string",
"restart_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"template_version_id": "0ba39c92-1f1b-4c32-aa3e-9925d7713eb1"
}
```
@ -173,6 +173,10 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
"allow_user_autostart": true,
"allow_user_autostop": true,
"allow_user_cancel_workspace_jobs": true,
"autostop_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"build_time_stats": {
"property1": {
"p50": 123,
@ -196,10 +200,6 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"provisioner": "terraform",
"restart_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"time_til_dormant_autodelete_ms": 0,
"time_til_dormant_ms": 0,
"updated_at": "2019-08-24T14:15:22Z"
@ -305,6 +305,10 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"allow_user_autostart": true,
"allow_user_autostop": true,
"allow_user_cancel_workspace_jobs": true,
"autostop_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"build_time_stats": {
"property1": {
"p50": 123,
@ -328,10 +332,6 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"provisioner": "terraform",
"restart_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"time_til_dormant_autodelete_ms": 0,
"time_til_dormant_ms": 0,
"updated_at": "2019-08-24T14:15:22Z"
@ -610,6 +610,10 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template} \
"allow_user_autostart": true,
"allow_user_autostop": true,
"allow_user_cancel_workspace_jobs": true,
"autostop_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"build_time_stats": {
"property1": {
"p50": 123,
@ -633,10 +637,6 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template} \
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"provisioner": "terraform",
"restart_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"time_til_dormant_autodelete_ms": 0,
"time_til_dormant_ms": 0,
"updated_at": "2019-08-24T14:15:22Z"
@ -725,6 +725,10 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \
"allow_user_autostart": true,
"allow_user_autostop": true,
"allow_user_cancel_workspace_jobs": true,
"autostop_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"build_time_stats": {
"property1": {
"p50": 123,
@ -748,10 +752,6 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \
"name": "string",
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
"provisioner": "terraform",
"restart_requirement": {
"days_of_week": ["monday"],
"weeks": 0
},
"time_til_dormant_autodelete_ms": 0,
"time_til_dormant_ms": 0,
"updated_at": "2019-08-24T14:15:22Z"

View File

@ -58,32 +58,32 @@ var auditableResourcesTypes = map[any]map[string]Action{
"public_key": ActionTrack, // Public keys are ok to expose in a diff.
},
&database.Template{}: {
"id": ActionTrack,
"created_at": ActionIgnore, // Never changes, but is implicit and not helpful in a diff.
"updated_at": ActionIgnore, // Changes, but is implicit and not helpful in a diff.
"organization_id": ActionIgnore, /// Never changes.
"deleted": ActionIgnore, // Changes, but is implicit when a delete event is fired.
"name": ActionTrack,
"display_name": ActionTrack,
"provisioner": ActionTrack,
"active_version_id": ActionTrack,
"description": ActionTrack,
"icon": ActionTrack,
"default_ttl": ActionTrack,
"max_ttl": ActionTrack,
"restart_requirement_days_of_week": ActionTrack,
"restart_requirement_weeks": ActionTrack,
"created_by": ActionTrack,
"created_by_username": ActionIgnore,
"created_by_avatar_url": ActionIgnore,
"group_acl": ActionTrack,
"user_acl": ActionTrack,
"allow_user_autostart": ActionTrack,
"allow_user_autostop": ActionTrack,
"allow_user_cancel_workspace_jobs": ActionTrack,
"failure_ttl": ActionTrack,
"time_til_dormant": ActionTrack,
"time_til_dormant_autodelete": ActionTrack,
"id": ActionTrack,
"created_at": ActionIgnore, // Never changes, but is implicit and not helpful in a diff.
"updated_at": ActionIgnore, // Changes, but is implicit and not helpful in a diff.
"organization_id": ActionIgnore, /// Never changes.
"deleted": ActionIgnore, // Changes, but is implicit when a delete event is fired.
"name": ActionTrack,
"display_name": ActionTrack,
"provisioner": ActionTrack,
"active_version_id": ActionTrack,
"description": ActionTrack,
"icon": ActionTrack,
"default_ttl": ActionTrack,
"max_ttl": ActionTrack,
"autostop_requirement_days_of_week": ActionTrack,
"autostop_requirement_weeks": ActionTrack,
"created_by": ActionTrack,
"created_by_username": ActionIgnore,
"created_by_avatar_url": ActionIgnore,
"group_acl": ActionTrack,
"user_acl": ActionTrack,
"allow_user_autostart": ActionTrack,
"allow_user_autostop": ActionTrack,
"allow_user_cancel_workspace_jobs": ActionTrack,
"failure_ttl": ActionTrack,
"time_til_dormant": ActionTrack,
"time_til_dormant_autodelete": ActionTrack,
},
&database.TemplateVersion{}: {
"id": ActionTrack,

View File

@ -265,7 +265,7 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
})
r.Route("/users/{user}/quiet-hours", func(r chi.Router) {
r.Use(
api.restartRequirementEnabledMW,
api.autostopRequirementEnabledMW,
apiKeyMiddleware,
httpmw.ExtractUserParam(options.Database, false),
)
@ -432,11 +432,11 @@ func (api *API) updateEntitlements(ctx context.Context) error {
codersdk.FeatureTemplateRBAC: api.RBAC,
codersdk.FeatureExternalProvisionerDaemons: true,
codersdk.FeatureAdvancedTemplateScheduling: true,
// FeatureTemplateRestartRequirement depends on
// FeatureTemplateAutostopRequirement depends on
// FeatureAdvancedTemplateScheduling.
codersdk.FeatureTemplateRestartRequirement: api.DefaultQuietHoursSchedule != "",
codersdk.FeatureWorkspaceProxy: true,
codersdk.FeatureUserRoleManagement: true,
codersdk.FeatureTemplateAutostopRequirement: api.DefaultQuietHoursSchedule != "",
codersdk.FeatureWorkspaceProxy: true,
codersdk.FeatureUserRoleManagement: true,
})
if err != nil {
return err
@ -455,15 +455,15 @@ func (api *API) updateEntitlements(ctx context.Context) error {
return nil
}
if entitlements.Features[codersdk.FeatureTemplateRestartRequirement].Enabled && !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
if entitlements.Features[codersdk.FeatureTemplateAutostopRequirement].Enabled && !entitlements.Features[codersdk.FeatureAdvancedTemplateScheduling].Enabled {
api.entitlements.Errors = []string{
`Your license is entitled to the feature "template restart ` +
`Your license is entitled to the feature "template autostop ` +
`requirement" (and you have it enabled by setting the ` +
"default quiet hours schedule), but you are not entitled to " +
`the dependency feature "advanced template scheduling". ` +
"Please contact support for a new license.",
}
api.Logger.Error(ctx, "license is entitled to template restart requirement but not advanced template scheduling")
api.Logger.Error(ctx, "license is entitled to template autostop requirement but not advanced template scheduling")
return nil
}
@ -524,30 +524,30 @@ func (api *API) updateEntitlements(ctx context.Context) error {
}
}
if initial, changed, enabled := featureChanged(codersdk.FeatureTemplateRestartRequirement); shouldUpdate(initial, changed, enabled) {
if initial, changed, enabled := featureChanged(codersdk.FeatureTemplateAutostopRequirement); shouldUpdate(initial, changed, enabled) {
if enabled {
templateStore := *(api.AGPL.TemplateScheduleStore.Load())
enterpriseTemplateStore, ok := templateStore.(*schedule.EnterpriseTemplateScheduleStore)
if !ok {
api.Logger.Error(ctx, "unable to set up enterprise template schedule store, template restart requirements will not be applied to workspace builds")
api.Logger.Error(ctx, "unable to set up enterprise template schedule store, template autostop requirements will not be applied to workspace builds")
}
enterpriseTemplateStore.UseRestartRequirement.Store(true)
enterpriseTemplateStore.UseAutostopRequirement.Store(true)
quietHoursStore, err := schedule.NewEnterpriseUserQuietHoursScheduleStore(api.DefaultQuietHoursSchedule)
if err != nil {
api.Logger.Error(ctx, "unable to set up enterprise user quiet hours schedule store, template restart requirements will not be applied to workspace builds", slog.Error(err))
api.Logger.Error(ctx, "unable to set up enterprise user quiet hours schedule store, template autostop requirements will not be applied to workspace builds", slog.Error(err))
} else {
api.AGPL.UserQuietHoursScheduleStore.Store(&quietHoursStore)
}
} else {
if api.DefaultQuietHoursSchedule != "" {
api.Logger.Warn(ctx, "template restart requirements are not enabled (due to setting default quiet hours schedule) as your license is not entitled to this feature")
api.Logger.Warn(ctx, "template autostop requirements are not enabled (due to setting default quiet hours schedule) as your license is not entitled to this feature")
}
templateStore := *(api.AGPL.TemplateScheduleStore.Load())
enterpriseTemplateStore, ok := templateStore.(*schedule.EnterpriseTemplateScheduleStore)
if ok {
enterpriseTemplateStore.UseRestartRequirement.Store(false)
enterpriseTemplateStore.UseAutostopRequirement.Store(false)
}
quietHoursStore := agplschedule.NewAGPLUserQuietHoursScheduleStore()

View File

@ -21,11 +21,11 @@ import (
// EnterpriseTemplateScheduleStore provides an agpl.TemplateScheduleStore that
// has all fields implemented for enterprise customers.
type EnterpriseTemplateScheduleStore struct {
// UseRestartRequirement decides whether the RestartRequirement field should
// be used instead of the MaxTTL field for determining the max deadline of a
// workspace build. This value is determined by a feature flag, licensing,
// and whether a default user quiet hours schedule is set.
UseRestartRequirement atomic.Bool
// UseAutostopRequirement decides whether the AutostopRequirement field
// should be used instead of the MaxTTL field for determining the max
// deadline of a workspace build. This value is determined by a feature
// flag, licensing, and whether a default user quiet hours schedule is set.
UseAutostopRequirement atomic.Bool
// UserQuietHoursScheduleStore is used when recalculating build deadlines on
// update.
@ -62,26 +62,26 @@ func (s *EnterpriseTemplateScheduleStore) Get(ctx context.Context, db database.S
// These extra checks have to be done before the conversion because we lose
// precision and signs when converting to the agpl types from the database.
if tpl.RestartRequirementDaysOfWeek < 0 {
return agpl.TemplateScheduleOptions{}, xerrors.New("invalid restart requirement days, negative")
if tpl.AutostopRequirementDaysOfWeek < 0 {
return agpl.TemplateScheduleOptions{}, xerrors.New("invalid autostop requirement days, negative")
}
if tpl.RestartRequirementDaysOfWeek > 0b11111111 {
return agpl.TemplateScheduleOptions{}, xerrors.New("invalid restart requirement days, too large")
if tpl.AutostopRequirementDaysOfWeek > 0b11111111 {
return agpl.TemplateScheduleOptions{}, xerrors.New("invalid autostop requirement days, too large")
}
err = agpl.VerifyTemplateRestartRequirement(uint8(tpl.RestartRequirementDaysOfWeek), tpl.RestartRequirementWeeks)
err = agpl.VerifyTemplateAutostopRequirement(uint8(tpl.AutostopRequirementDaysOfWeek), tpl.AutostopRequirementWeeks)
if err != nil {
return agpl.TemplateScheduleOptions{}, err
}
return agpl.TemplateScheduleOptions{
UserAutostartEnabled: tpl.AllowUserAutostart,
UserAutostopEnabled: tpl.AllowUserAutostop,
DefaultTTL: time.Duration(tpl.DefaultTTL),
MaxTTL: time.Duration(tpl.MaxTTL),
UseRestartRequirement: s.UseRestartRequirement.Load(),
RestartRequirement: agpl.TemplateRestartRequirement{
DaysOfWeek: uint8(tpl.RestartRequirementDaysOfWeek),
Weeks: tpl.RestartRequirementWeeks,
UserAutostartEnabled: tpl.AllowUserAutostart,
UserAutostopEnabled: tpl.AllowUserAutostop,
DefaultTTL: time.Duration(tpl.DefaultTTL),
MaxTTL: time.Duration(tpl.MaxTTL),
UseAutostopRequirement: s.UseAutostopRequirement.Load(),
AutostopRequirement: agpl.TemplateAutostopRequirement{
DaysOfWeek: uint8(tpl.AutostopRequirementDaysOfWeek),
Weeks: tpl.AutostopRequirementWeeks,
},
FailureTTL: time.Duration(tpl.FailureTTL),
TimeTilDormant: time.Duration(tpl.TimeTilDormant),
@ -96,8 +96,8 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
if int64(opts.DefaultTTL) == tpl.DefaultTTL &&
int64(opts.MaxTTL) == tpl.MaxTTL &&
int16(opts.RestartRequirement.DaysOfWeek) == tpl.RestartRequirementDaysOfWeek &&
opts.RestartRequirement.Weeks == tpl.RestartRequirementWeeks &&
int16(opts.AutostopRequirement.DaysOfWeek) == tpl.AutostopRequirementDaysOfWeek &&
opts.AutostopRequirement.Weeks == tpl.AutostopRequirementWeeks &&
int64(opts.FailureTTL) == tpl.FailureTTL &&
int64(opts.TimeTilDormant) == tpl.TimeTilDormant &&
int64(opts.TimeTilDormantAutoDelete) == tpl.TimeTilDormantAutoDelete &&
@ -107,7 +107,7 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
return tpl, nil
}
err := agpl.VerifyTemplateRestartRequirement(opts.RestartRequirement.DaysOfWeek, opts.RestartRequirement.Weeks)
err := agpl.VerifyTemplateAutostopRequirement(opts.AutostopRequirement.DaysOfWeek, opts.AutostopRequirement.Weeks)
if err != nil {
return database.Template{}, err
}
@ -118,17 +118,17 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
defer span.End()
err := tx.UpdateTemplateScheduleByID(ctx, database.UpdateTemplateScheduleByIDParams{
ID: tpl.ID,
UpdatedAt: s.now(),
AllowUserAutostart: opts.UserAutostartEnabled,
AllowUserAutostop: opts.UserAutostopEnabled,
DefaultTTL: int64(opts.DefaultTTL),
MaxTTL: int64(opts.MaxTTL),
RestartRequirementDaysOfWeek: int16(opts.RestartRequirement.DaysOfWeek),
RestartRequirementWeeks: opts.RestartRequirement.Weeks,
FailureTTL: int64(opts.FailureTTL),
TimeTilDormant: int64(opts.TimeTilDormant),
TimeTilDormantAutoDelete: int64(opts.TimeTilDormantAutoDelete),
ID: tpl.ID,
UpdatedAt: s.now(),
AllowUserAutostart: opts.UserAutostartEnabled,
AllowUserAutostop: opts.UserAutostopEnabled,
DefaultTTL: int64(opts.DefaultTTL),
MaxTTL: int64(opts.MaxTTL),
AutostopRequirementDaysOfWeek: int16(opts.AutostopRequirement.DaysOfWeek),
AutostopRequirementWeeks: opts.AutostopRequirement.Weeks,
FailureTTL: int64(opts.FailureTTL),
TimeTilDormant: int64(opts.TimeTilDormant),
TimeTilDormantAutoDelete: int64(opts.TimeTilDormantAutoDelete),
})
if err != nil {
return xerrors.Errorf("update template schedule: %w", err)
@ -170,7 +170,7 @@ func (s *EnterpriseTemplateScheduleStore) Set(ctx context.Context, db database.S
// Recalculate max_deadline and deadline for all running workspace
// builds on this template.
if s.UseRestartRequirement.Load() {
if s.UseAutostopRequirement.Load() {
err = s.updateWorkspaceBuilds(ctx, tx, template)
if err != nil {
return xerrors.Errorf("update workspace builds: %w", err)
@ -238,7 +238,7 @@ func (s *EnterpriseTemplateScheduleStore) updateWorkspaceBuild(ctx context.Conte
// If the job completed before the autostop epoch, then it must be skipped
// to avoid failures below. Add a week to account for timezones.
if job.CompletedAt.Time.Before(agpl.TemplateRestartRequirementEpoch(time.UTC).Add(time.Hour * 7 * 24)) {
if job.CompletedAt.Time.Before(agpl.TemplateAutostopRequirementEpoch(time.UTC).Add(time.Hour * 7 * 24)) {
return nil
}

View File

@ -210,17 +210,17 @@ func TestTemplateUpdateBuildDeadlines(t *testing.T) {
// Set the template policy.
templateScheduleStore := schedule.NewEnterpriseTemplateScheduleStore(userQuietHoursStorePtr)
templateScheduleStore.UseRestartRequirement.Store(true)
templateScheduleStore.UseAutostopRequirement.Store(true)
templateScheduleStore.TimeNowFn = func() time.Time {
return c.now
}
_, err = templateScheduleStore.Set(ctx, db, template, agplschedule.TemplateScheduleOptions{
UserAutostartEnabled: false,
UserAutostopEnabled: false,
DefaultTTL: 0,
MaxTTL: 0,
UseRestartRequirement: true,
RestartRequirement: agplschedule.TemplateRestartRequirement{
UserAutostartEnabled: false,
UserAutostopEnabled: false,
DefaultTTL: 0,
MaxTTL: 0,
UseAutostopRequirement: true,
AutostopRequirement: agplschedule.TemplateAutostopRequirement{
// Every day
DaysOfWeek: 0b01111111,
Weeks: 0,
@ -485,17 +485,17 @@ func TestTemplateUpdateBuildDeadlinesSkip(t *testing.T) {
// Set the template policy.
templateScheduleStore := schedule.NewEnterpriseTemplateScheduleStore(userQuietHoursStorePtr)
templateScheduleStore.UseRestartRequirement.Store(true)
templateScheduleStore.UseAutostopRequirement.Store(true)
templateScheduleStore.TimeNowFn = func() time.Time {
return now
}
_, err = templateScheduleStore.Set(ctx, db, template, agplschedule.TemplateScheduleOptions{
UserAutostartEnabled: false,
UserAutostopEnabled: false,
DefaultTTL: 0,
MaxTTL: 0,
UseRestartRequirement: true,
RestartRequirement: agplschedule.TemplateRestartRequirement{
UserAutostartEnabled: false,
UserAutostopEnabled: false,
DefaultTTL: 0,
MaxTTL: 0,
UseAutostopRequirement: true,
AutostopRequirement: agplschedule.TemplateAutostopRequirement{
// Every day
DaysOfWeek: 0b01111111,
Weeks: 0,

View File

@ -140,7 +140,7 @@ func TestTemplates(t *testing.T) {
require.EqualValues(t, exp, *ws.TTLMillis)
})
t.Run("SetRestartRequirement", func(t *testing.T) {
t.Run("SetAutostopRequirement", func(t *testing.T) {
t.Parallel()
client, user := coderdenttest.New(t, &coderdenttest.Options{
@ -157,8 +157,8 @@ func TestTemplates(t *testing.T) {
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
require.Empty(t, 0, template.RestartRequirement.DaysOfWeek)
require.Zero(t, template.RestartRequirement.Weeks)
require.Empty(t, 0, template.AutostopRequirement.DaysOfWeek)
require.Zero(t, template.AutostopRequirement.Weeks)
// ctx := testutil.Context(t, testutil.WaitLong)
ctx := context.Background()
@ -169,19 +169,19 @@ func TestTemplates(t *testing.T) {
Icon: template.Icon,
AllowUserCancelWorkspaceJobs: template.AllowUserCancelWorkspaceJobs,
DefaultTTLMillis: time.Hour.Milliseconds(),
RestartRequirement: &codersdk.TemplateRestartRequirement{
AutostopRequirement: &codersdk.TemplateAutostopRequirement{
DaysOfWeek: []string{"monday", "saturday"},
Weeks: 3,
},
})
require.NoError(t, err)
require.Equal(t, []string{"monday", "saturday"}, updated.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 3, updated.RestartRequirement.Weeks)
require.Equal(t, []string{"monday", "saturday"}, updated.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 3, updated.AutostopRequirement.Weeks)
template, err = client.Template(ctx, template.ID)
require.NoError(t, err)
require.Equal(t, []string{"monday", "saturday"}, template.RestartRequirement.DaysOfWeek)
require.EqualValues(t, 3, template.RestartRequirement.Weeks)
require.Equal(t, []string{"monday", "saturday"}, template.AutostopRequirement.DaysOfWeek)
require.EqualValues(t, 3, template.AutostopRequirement.Weeks)
})
t.Run("CleanupTTLs", func(t *testing.T) {

View File

@ -11,28 +11,28 @@ import (
"github.com/coder/coder/v2/codersdk"
)
func (api *API) restartRequirementEnabledMW(next http.Handler) http.Handler {
func (api *API) autostopRequirementEnabledMW(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// The experiment must be enabled.
if !api.AGPL.Experiments.Enabled(codersdk.ExperimentTemplateRestartRequirement) {
if !api.AGPL.Experiments.Enabled(codersdk.ExperimentTemplateAutostopRequirement) {
httpapi.RouteNotFound(rw)
return
}
// Entitlement must be enabled.
api.entitlementsMu.RLock()
entitled := api.entitlements.Features[codersdk.FeatureTemplateRestartRequirement].Entitlement != codersdk.EntitlementNotEntitled
enabled := api.entitlements.Features[codersdk.FeatureTemplateRestartRequirement].Enabled
entitled := api.entitlements.Features[codersdk.FeatureTemplateAutostopRequirement].Entitlement != codersdk.EntitlementNotEntitled
enabled := api.entitlements.Features[codersdk.FeatureTemplateAutostopRequirement].Enabled
api.entitlementsMu.RUnlock()
if !entitled {
httpapi.Write(r.Context(), rw, http.StatusForbidden, codersdk.Response{
Message: "Template restart requirement is an Enterprise feature. Contact sales!",
Message: "Template autostop requirement is an Enterprise feature. Contact sales!",
})
return
}
if !enabled {
httpapi.Write(r.Context(), rw, http.StatusForbidden, codersdk.Response{
Message: "Template restart requirement feature is not enabled. Please specify a default user quiet hours schedule to use this feature.",
Message: "Template autostop requirement feature is not enabled. Please specify a default user quiet hours schedule to use this feature.",
})
return
}

View File

@ -35,7 +35,7 @@ func TestUserQuietHours(t *testing.T) {
dv := coderdtest.DeploymentValues(t)
dv.UserQuietHoursSchedule.DefaultSchedule.Set(defaultQuietHoursSchedule)
dv.Experiments.Set(string(codersdk.ExperimentTemplateRestartRequirement))
dv.Experiments.Set(string(codersdk.ExperimentTemplateAutostopRequirement))
client, user := coderdenttest.New(t, &coderdenttest.Options{
Options: &coderdtest.Options{
@ -43,8 +43,8 @@ func TestUserQuietHours(t *testing.T) {
},
LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{
codersdk.FeatureAdvancedTemplateScheduling: 1,
codersdk.FeatureTemplateRestartRequirement: 1,
codersdk.FeatureAdvancedTemplateScheduling: 1,
codersdk.FeatureTemplateAutostopRequirement: 1,
},
},
})
@ -133,7 +133,7 @@ func TestUserQuietHours(t *testing.T) {
dv := coderdtest.DeploymentValues(t)
dv.UserQuietHoursSchedule.DefaultSchedule.Set("CRON_TZ=America/Chicago 0 0 * * *")
dv.Experiments.Set(string(codersdk.ExperimentTemplateRestartRequirement))
dv.Experiments.Set(string(codersdk.ExperimentTemplateAutostopRequirement))
client, user := coderdenttest.New(t, &coderdenttest.Options{
Options: &coderdtest.Options{
@ -143,7 +143,7 @@ func TestUserQuietHours(t *testing.T) {
Features: license.Features{
codersdk.FeatureAdvancedTemplateScheduling: 1,
// Not entitled.
// codersdk.FeatureTemplateRestartRequirement: 1,
// codersdk.FeatureTemplateAutostopRequirement: 1,
},
},
})
@ -161,7 +161,7 @@ func TestUserQuietHours(t *testing.T) {
dv := coderdtest.DeploymentValues(t)
dv.UserQuietHoursSchedule.DefaultSchedule.Set("")
dv.Experiments.Set(string(codersdk.ExperimentTemplateRestartRequirement))
dv.Experiments.Set(string(codersdk.ExperimentTemplateAutostopRequirement))
client, user := coderdenttest.New(t, &coderdenttest.Options{
NoDefaultQuietHoursSchedule: true,
@ -170,8 +170,8 @@ func TestUserQuietHours(t *testing.T) {
},
LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{
codersdk.FeatureAdvancedTemplateScheduling: 1,
codersdk.FeatureTemplateRestartRequirement: 1,
codersdk.FeatureAdvancedTemplateScheduling: 1,
codersdk.FeatureTemplateAutostopRequirement: 1,
},
},
})
@ -197,8 +197,8 @@ func TestUserQuietHours(t *testing.T) {
},
LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{
codersdk.FeatureAdvancedTemplateScheduling: 1,
codersdk.FeatureTemplateRestartRequirement: 1,
codersdk.FeatureAdvancedTemplateScheduling: 1,
codersdk.FeatureTemplateAutostopRequirement: 1,
},
},
})

View File

@ -195,7 +195,7 @@ export interface CreateTemplateRequest {
readonly template_version_id: string
readonly default_ttl_ms?: number
readonly max_ttl_ms?: number
readonly restart_requirement?: TemplateRestartRequirement
readonly autostop_requirement?: TemplateAutostopRequirement
readonly allow_user_cancel_workspace_jobs?: boolean
readonly allow_user_autostart?: boolean
readonly allow_user_autostop?: boolean
@ -910,7 +910,7 @@ export interface Template {
readonly icon: string
readonly default_ttl_ms: number
readonly max_ttl_ms: number
readonly restart_requirement: TemplateRestartRequirement
readonly autostop_requirement: TemplateAutostopRequirement
readonly created_by_id: string
readonly created_by_name: string
readonly allow_user_autostart: boolean
@ -937,6 +937,12 @@ export interface TemplateAppUsage {
readonly seconds: number
}
// From codersdk/templates.go
export interface TemplateAutostopRequirement {
readonly days_of_week: string[]
readonly weeks: number
}
// From codersdk/templates.go
export type TemplateBuildTimeStats = Record<
WorkspaceTransition,
@ -1009,12 +1015,6 @@ export interface TemplateParameterValue {
readonly count: number
}
// From codersdk/templates.go
export interface TemplateRestartRequirement {
readonly days_of_week: string[]
readonly weeks: number
}
// From codersdk/templates.go
export interface TemplateUser extends User {
readonly role: TemplateRole
@ -1147,7 +1147,7 @@ export interface UpdateTemplateMeta {
readonly icon?: string
readonly default_ttl_ms?: number
readonly max_ttl_ms?: number
readonly restart_requirement?: TemplateRestartRequirement
readonly autostop_requirement?: TemplateAutostopRequirement
readonly allow_user_autostart?: boolean
readonly allow_user_autostop?: boolean
readonly allow_user_cancel_workspace_jobs?: boolean
@ -1603,7 +1603,7 @@ export type Experiment =
| "moons"
| "single_tailnet"
| "tailnet_pg_coordinator"
| "template_restart_requirement"
| "template_autostop_requirement"
| "workspace_actions"
| "workspaces_batch_actions"
export const Experiments: Experiment[] = [
@ -1611,7 +1611,7 @@ export const Experiments: Experiment[] = [
"moons",
"single_tailnet",
"tailnet_pg_coordinator",
"template_restart_requirement",
"template_autostop_requirement",
"workspace_actions",
"workspaces_batch_actions",
]
@ -1626,8 +1626,8 @@ export type FeatureName =
| "high_availability"
| "multiple_git_auth"
| "scim"
| "template_autostop_requirement"
| "template_rbac"
| "template_restart_requirement"
| "user_limit"
| "user_role_management"
| "workspace_proxy"
@ -1640,8 +1640,8 @@ export const FeatureNames: FeatureName[] = [
"high_availability",
"multiple_git_auth",
"scim",
"template_autostop_requirement",
"template_rbac",
"template_restart_requirement",
"user_limit",
"user_role_management",
"workspace_proxy",

View File

@ -26,7 +26,7 @@ const validFormValues: FormValues = {
allow_user_cancel_workspace_jobs: false,
allow_user_autostart: false,
allow_user_autostop: false,
restart_requirement: {
autostop_requirement: {
days_of_week: [],
weeks: 1,
},

View File

@ -74,9 +74,9 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
? template.time_til_dormant_autodelete_ms / MS_DAY_CONVERSION
: 0,
restart_requirement: {
days_of_week: template.restart_requirement.days_of_week,
weeks: template.restart_requirement.weeks,
autostop_requirement: {
days_of_week: template.autostop_requirement.days_of_week,
weeks: template.autostop_requirement.weeks,
},
allow_user_autostart: template.allow_user_autostart,

View File

@ -436,7 +436,7 @@ export const MockTemplate: TypesGen.Template = {
description: "This is a test description.",
default_ttl_ms: 24 * 60 * 60 * 1000,
max_ttl_ms: 2 * 24 * 60 * 60 * 1000,
restart_requirement: {
autostop_requirement: {
days_of_week: [],
weeks: 1,
},