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

This commit is contained in:
Dean Sheather
2023-08-29 18:35:05 +00:00
committed by GitHub
parent fc4683d8b3
commit a572800d47
40 changed files with 925 additions and 891 deletions
+14 -14
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()
+34 -34
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
}
+14 -14
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,
+8 -8
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) {
+6 -6
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
}
+10 -10
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,
},
},
})