Skip to content

Commit 39c0539

Browse files
authored
feat: add controls to template for determining startup days (#10226)
* feat: template controls which days can autostart * Add unit test to test blocking autostart with DaysOfWeek
1 parent 98b6c8b commit 39c0539

32 files changed

+825
-144
lines changed

cli/templateedit.go

+42-14
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,20 @@ import (
1717

1818
func (r *RootCmd) templateEdit() *clibase.Cmd {
1919
var (
20-
name string
21-
displayName string
22-
description string
23-
icon string
24-
defaultTTL time.Duration
25-
maxTTL time.Duration
26-
autostopRequirementDaysOfWeek []string
27-
autostopRequirementWeeks int64
28-
failureTTL time.Duration
29-
inactivityTTL time.Duration
30-
allowUserCancelWorkspaceJobs bool
31-
allowUserAutostart bool
32-
allowUserAutostop bool
20+
name string
21+
displayName string
22+
description string
23+
icon string
24+
defaultTTL time.Duration
25+
maxTTL time.Duration
26+
autostopRequirementDaysOfWeek []string
27+
autostopRequirementWeeks int64
28+
autostartRequirementDaysOfWeek []string
29+
failureTTL time.Duration
30+
inactivityTTL time.Duration
31+
allowUserCancelWorkspaceJobs bool
32+
allowUserAutostart bool
33+
allowUserAutostop bool
3334
)
3435
client := new(codersdk.Client)
3536

@@ -48,7 +49,9 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
4849
!allowUserAutostop ||
4950
maxTTL != 0 ||
5051
failureTTL != 0 ||
51-
inactivityTTL != 0
52+
inactivityTTL != 0 ||
53+
len(autostartRequirementDaysOfWeek) > 0
54+
5255
if requiresEntitlement {
5356
entitlements, err := client.Entitlements(inv.Context())
5457
var sdkErr *codersdk.Error
@@ -77,6 +80,12 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
7780
if len(autostopRequirementDaysOfWeek) == 0 {
7881
autostopRequirementDaysOfWeek = template.AutostopRequirement.DaysOfWeek
7982
}
83+
if len(autostartRequirementDaysOfWeek) == 1 && autostartRequirementDaysOfWeek[0] == "all" {
84+
// Set it to every day of the week
85+
autostartRequirementDaysOfWeek = []string{"monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"}
86+
} else if len(autostartRequirementDaysOfWeek) == 0 {
87+
autostartRequirementDaysOfWeek = template.AutostartRequirement.DaysOfWeek
88+
}
8089
if unsetAutostopRequirementDaysOfWeek {
8190
autostopRequirementDaysOfWeek = []string{}
8291
}
@@ -93,6 +102,9 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
93102
DaysOfWeek: autostopRequirementDaysOfWeek,
94103
Weeks: autostopRequirementWeeks,
95104
},
105+
AutostartRequirement: &codersdk.TemplateAutostartRequirement{
106+
DaysOfWeek: autostartRequirementDaysOfWeek,
107+
},
96108
FailureTTLMillis: failureTTL.Milliseconds(),
97109
TimeTilDormantMillis: inactivityTTL.Milliseconds(),
98110
AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
@@ -140,6 +152,22 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
140152
Description: "Edit the template maximum time before shutdown - workspaces created from this template must shutdown within the given duration after starting, regardless of user activity. This is an enterprise-only feature. Maps to \"Max lifetime\" in the UI.",
141153
Value: clibase.DurationOf(&maxTTL),
142154
},
155+
{
156+
Flag: "autostart-requirement-weekdays",
157+
// 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'.
158+
Description: "Edit the template autostart requirement weekdays - workspaces created from this template can only autostart on the given weekdays. To unset this value for the template (and allow autostart on all days), pass 'all'.",
159+
Value: clibase.Validate(clibase.StringArrayOf(&autostartRequirementDaysOfWeek), func(value *clibase.StringArray) error {
160+
v := value.GetSlice()
161+
if len(v) == 1 && v[0] == "all" {
162+
return nil
163+
}
164+
_, err := codersdk.WeekdaysToBitmap(v)
165+
if err != nil {
166+
return xerrors.Errorf("invalid autostart requirement days of week %q: %w", strings.Join(v, ","), err)
167+
}
168+
return nil
169+
}),
170+
},
143171
{
144172
Flag: "autostop-requirement-weekdays",
145173
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'.",

cli/templateedit_test.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ func TestTemplateEdit(t *testing.T) {
248248
assert.Equal(t, "", updated.Icon)
249249
assert.Equal(t, "", updated.DisplayName)
250250
})
251-
t.Run("AutostopRequirement", func(t *testing.T) {
251+
t.Run("Autostop/startRequirement", func(t *testing.T) {
252252
t.Parallel()
253253
t.Run("BlockedAGPL", func(t *testing.T) {
254254
t.Parallel()
@@ -286,6 +286,12 @@ func TestTemplateEdit(t *testing.T) {
286286
"--autostop-requirement-weeks", "1",
287287
},
288288
},
289+
{
290+
name: "AutostartDays",
291+
flags: []string{
292+
"--autostart-requirement-weekdays", "monday",
293+
},
294+
},
289295
}
290296

291297
for _, c := range cases {
@@ -321,6 +327,8 @@ func TestTemplateEdit(t *testing.T) {
321327
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
322328
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
323329
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
330+
assert.Equal(t, template.AutostartRequirement.DaysOfWeek, updated.AutostartRequirement.DaysOfWeek)
331+
assert.Equal(t, template.AutostartRequirement.DaysOfWeek, updated.AutostartRequirement.DaysOfWeek)
324332
})
325333
}
326334
})
@@ -436,6 +444,7 @@ func TestTemplateEdit(t *testing.T) {
436444
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
437445
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
438446
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
447+
assert.Equal(t, template.AutostartRequirement.DaysOfWeek, updated.AutostartRequirement.DaysOfWeek)
439448
})
440449
}
441450
})
@@ -536,6 +545,7 @@ func TestTemplateEdit(t *testing.T) {
536545
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
537546
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
538547
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
548+
assert.Equal(t, template.AutostartRequirement.DaysOfWeek, updated.AutostartRequirement.DaysOfWeek)
539549
})
540550
})
541551
// TODO(@dean): remove this test when we remove max_ttl
@@ -808,6 +818,7 @@ func TestTemplateEdit(t *testing.T) {
808818
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
809819
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
810820
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
821+
assert.Equal(t, template.AutostartRequirement.DaysOfWeek, updated.AutostartRequirement.DaysOfWeek)
811822
assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
812823
assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
813824
assert.Equal(t, template.FailureTTLMillis, updated.FailureTTLMillis)
@@ -903,6 +914,7 @@ func TestTemplateEdit(t *testing.T) {
903914
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
904915
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
905916
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
917+
assert.Equal(t, template.AutostartRequirement.DaysOfWeek, updated.AutostartRequirement.DaysOfWeek)
906918
assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
907919
assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
908920
assert.Equal(t, template.FailureTTLMillis, updated.FailureTTLMillis)
@@ -1002,6 +1014,7 @@ func TestTemplateEdit(t *testing.T) {
10021014
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
10031015
assert.Equal(t, template.AutostopRequirement.DaysOfWeek, updated.AutostopRequirement.DaysOfWeek)
10041016
assert.Equal(t, template.AutostopRequirement.Weeks, updated.AutostopRequirement.Weeks)
1017+
assert.Equal(t, template.AutostartRequirement.DaysOfWeek, updated.AutostartRequirement.DaysOfWeek)
10051018
assert.Equal(t, template.AllowUserAutostart, updated.AllowUserAutostart)
10061019
assert.Equal(t, template.AllowUserAutostop, updated.AllowUserAutostop)
10071020
assert.Equal(t, template.FailureTTLMillis, updated.FailureTTLMillis)

cli/testdata/coder_templates_edit_--help.golden

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ OPTIONS:
1717
--allow-user-cancel-workspace-jobs bool (default: true)
1818
Allow users to cancel in-progress workspace jobs.
1919

20+
--autostart-requirement-weekdays string-array
21+
Edit the template autostart requirement weekdays - workspaces created
22+
from this template can only autostart on the given weekdays. To unset
23+
this value for the template (and allow autostart on all days), pass
24+
'all'.
25+
2026
--default-ttl duration
2127
Edit the template default time before shutdown - workspaces created
2228
from this template default to this value. Maps to "Default autostop"

coderd/apidoc/docs.go

+33-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

+33-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/autobuild/lifecycle_executor.go

+11
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,17 @@ func isEligibleForAutostart(ws database.Workspace, build database.WorkspaceBuild
354354
// Truncate is probably not necessary here, but doing it anyway to be sure.
355355
nextTransition := sched.Next(build.CreatedAt).Truncate(time.Minute)
356356

357+
// The nextTransition is when the auto start should kick off. If it lands on a
358+
// forbidden day, do not allow the auto start. We use the time location of the
359+
// schedule to determine the weekday. So if "Saturday" is disallowed, the
360+
// definition of "Saturday" depends on the location of the schedule.
361+
zonedTransition := nextTransition.In(sched.Location())
362+
allowed := templateSchedule.AutostartRequirement.DaysMap()[zonedTransition.Weekday()]
363+
if !allowed {
364+
return false
365+
}
366+
367+
// Must used '.Before' vs '.After' so equal times are considered "valid for autostart".
357368
return !currentTick.Before(nextTransition)
358369
}
359370

0 commit comments

Comments
 (0)