Skip to content

Commit dc8b731

Browse files
authored
feat: add user quiet hours schedule and restart requirement feature flag (#8115)
1 parent 4821e2e commit dc8b731

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+4325
-752
lines changed

cli/create.go

-2
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,6 @@ func (r *RootCmd) create() *clibase.Cmd {
149149
var ttlMillis *int64
150150
if stopAfter > 0 {
151151
ttlMillis = ptr.Ref(stopAfter.Milliseconds())
152-
} else if template.MaxTTLMillis > 0 {
153-
ttlMillis = &template.MaxTTLMillis
154152
}
155153

156154
workspace, err := client.CreateWorkspace(inv.Context(), organization.ID, workspaceOwner, codersdk.CreateWorkspaceRequest{

cli/schedule_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ func TestScheduleOverride(t *testing.T) {
316316
stdoutBuf = &bytes.Buffer{}
317317
)
318318
require.Zero(t, template.DefaultTTLMillis)
319-
require.Zero(t, template.MaxTTLMillis)
319+
require.Empty(t, template.RestartRequirement.DaysOfWeek)
320+
require.Zero(t, template.RestartRequirement.Weeks)
320321

321322
// Unset the workspace TTL
322323
err = client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{TTLMillis: nil})

cli/server.go

+1
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
496496
FilesRateLimit: filesRateLimit,
497497
HTTPClient: httpClient,
498498
TemplateScheduleStore: &atomic.Pointer[schedule.TemplateScheduleStore]{},
499+
UserQuietHoursScheduleStore: &atomic.Pointer[schedule.UserQuietHoursScheduleStore]{},
499500
SSHConfig: codersdk.SSHConfigResponse{
500501
HostnamePrefix: cfg.SSHConfig.DeploymentName.String(),
501502
SSHConfigOptions: configSSHOptions,

cli/templateedit.go

+55-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cli
33
import (
44
"fmt"
55
"net/http"
6+
"strings"
67
"time"
78

89
"golang.org/x/xerrors"
@@ -20,6 +21,8 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
2021
icon string
2122
defaultTTL time.Duration
2223
maxTTL time.Duration
24+
restartRequirementDaysOfWeek []string
25+
restartRequirementWeeks int64
2326
failureTTL time.Duration
2427
inactivityTTL time.Duration
2528
allowUserCancelWorkspaceJobs bool
@@ -48,7 +51,15 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
4851
}
4952
}
5053

51-
if maxTTL != 0 || !allowUserAutostart || !allowUserAutostop || failureTTL != 0 || inactivityTTL != 0 {
54+
unsetRestartRequirementDaysOfWeek := len(restartRequirementDaysOfWeek) == 1 && restartRequirementDaysOfWeek[0] == "none"
55+
requiresEntitlement := (len(restartRequirementDaysOfWeek) > 0 && !unsetRestartRequirementDaysOfWeek) ||
56+
restartRequirementWeeks > 0 ||
57+
!allowUserAutostart ||
58+
!allowUserAutostop ||
59+
maxTTL != 0 ||
60+
failureTTL != 0 ||
61+
inactivityTTL != 0
62+
if requiresEntitlement {
5263
entitlements, err := client.Entitlements(inv.Context())
5364
var sdkErr *codersdk.Error
5465
if xerrors.As(err, &sdkErr) && sdkErr.StatusCode() == http.StatusNotFound {
@@ -71,14 +82,27 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
7182
return xerrors.Errorf("get workspace template: %w", err)
7283
}
7384

85+
// Copy the default value if the list is empty, or if the user
86+
// specified the "none" value clear the list.
87+
if len(restartRequirementDaysOfWeek) == 0 {
88+
restartRequirementDaysOfWeek = template.RestartRequirement.DaysOfWeek
89+
}
90+
if unsetRestartRequirementDaysOfWeek {
91+
restartRequirementDaysOfWeek = []string{}
92+
}
93+
7494
// NOTE: coderd will ignore empty fields.
7595
req := codersdk.UpdateTemplateMeta{
76-
Name: name,
77-
DisplayName: displayName,
78-
Description: description,
79-
Icon: icon,
80-
DefaultTTLMillis: defaultTTL.Milliseconds(),
81-
MaxTTLMillis: maxTTL.Milliseconds(),
96+
Name: name,
97+
DisplayName: displayName,
98+
Description: description,
99+
Icon: icon,
100+
DefaultTTLMillis: defaultTTL.Milliseconds(),
101+
MaxTTLMillis: maxTTL.Milliseconds(),
102+
RestartRequirement: &codersdk.TemplateRestartRequirement{
103+
DaysOfWeek: restartRequirementDaysOfWeek,
104+
Weeks: restartRequirementWeeks,
105+
},
82106
FailureTTLMillis: failureTTL.Milliseconds(),
83107
InactivityTTLMillis: inactivityTTL.Milliseconds(),
84108
AllowUserCancelWorkspaceJobs: allowUserCancelWorkspaceJobs,
@@ -126,6 +150,30 @@ func (r *RootCmd) templateEdit() *clibase.Cmd {
126150
Description: "Edit the template maximum time before shutdown - workspaces created from this template must shutdown within the given duration after starting. This is an enterprise-only feature.",
127151
Value: clibase.DurationOf(&maxTTL),
128152
},
153+
{
154+
Flag: "restart-requirement-weekdays",
155+
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'.",
156+
// TODO(@dean): unhide when we delete max_ttl
157+
Hidden: true,
158+
Value: clibase.Validate(clibase.StringArrayOf(&restartRequirementDaysOfWeek), func(value *clibase.StringArray) error {
159+
v := value.GetSlice()
160+
if len(v) == 1 && v[0] == "none" {
161+
return nil
162+
}
163+
_, err := codersdk.WeekdaysToBitmap(v)
164+
if err != nil {
165+
return xerrors.Errorf("invalid restart requirement days of week %q: %w", strings.Join(v, ","), err)
166+
}
167+
return nil
168+
}),
169+
},
170+
{
171+
Flag: "restart-requirement-weeks",
172+
Description: "Edit the template restart requirement weeks - workspaces created from this template must be restarted on an n-weekly basis.",
173+
// TODO(@dean): unhide when we delete max_ttl
174+
Hidden: true,
175+
Value: clibase.Int64Of(&restartRequirementWeeks),
176+
},
129177
{
130178
Flag: "failure-ttl",
131179
Description: "Specify a failure TTL for workspaces created from this template. This licensed feature's default is 0h (off).",

0 commit comments

Comments
 (0)