mirror of
https://github.com/coder/coder.git
synced 2025-07-13 21:36:50 +00:00
feat: add default autostart and ttl for new workspaces (#1632)
* database: add autostart_schedule and ttl to InsertWorkspace; make gen * coderd: workspaces: consume additional fields of CreateWorkspaceRequest * cli: update: add support for TTL and autostart_schedule * cli: create: add unit tests * coder: import `time/tzdata` for embedded timezone database * autobuild: fix unit test that only runs with a real db
This commit is contained in:
@ -36,9 +36,6 @@ func TestExecutorAutostartOK(t *testing.T) {
|
||||
// Given: workspace is stopped
|
||||
workspace = mustTransitionWorkspace(t, client, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Given: the workspace initially has autostart disabled
|
||||
require.Empty(t, workspace.AutostartSchedule)
|
||||
|
||||
// When: we enable workspace autostart
|
||||
sched, err := schedule.Weekly("* * * * *")
|
||||
require.NoError(t, err)
|
||||
@ -77,9 +74,6 @@ func TestExecutorAutostartTemplateUpdated(t *testing.T) {
|
||||
// Given: workspace is stopped
|
||||
workspace = mustTransitionWorkspace(t, client, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Given: the workspace initially has autostart disabled
|
||||
require.Empty(t, workspace.AutostartSchedule)
|
||||
|
||||
// Given: the workspace template has been updated
|
||||
orgs, err := client.OrganizationsByUser(ctx, workspace.OwnerID.String())
|
||||
require.NoError(t, err)
|
||||
@ -131,9 +125,6 @@ func TestExecutorAutostartAlreadyRunning(t *testing.T) {
|
||||
// Given: we ensure the workspace is running
|
||||
require.Equal(t, codersdk.WorkspaceTransitionStart, workspace.LatestBuild.Transition)
|
||||
|
||||
// Given: the workspace initially has autostart disabled
|
||||
require.Empty(t, workspace.AutostartSchedule)
|
||||
|
||||
// When: we enable workspace autostart
|
||||
sched, err := schedule.Weekly("* * * * *")
|
||||
require.NoError(t, err)
|
||||
@ -164,15 +155,17 @@ func TestExecutorAutostartNotEnabled(t *testing.T) {
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
// Given: we have a user with a workspace
|
||||
workspace = mustProvisionWorkspace(t, client)
|
||||
workspace = mustProvisionWorkspace(t, client, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.AutostartSchedule = nil
|
||||
})
|
||||
)
|
||||
|
||||
// Given: workspace does not have autostart enabled
|
||||
require.Empty(t, workspace.AutostartSchedule)
|
||||
|
||||
// Given: workspace is stopped
|
||||
workspace = mustTransitionWorkspace(t, client, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Given: the workspace has autostart disabled
|
||||
require.Empty(t, workspace.AutostartSchedule)
|
||||
|
||||
// When: the autobuild executor ticks
|
||||
go func() {
|
||||
tickCh <- time.Now().UTC().Add(time.Minute)
|
||||
@ -190,8 +183,6 @@ func TestExecutorAutostopOK(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
err error
|
||||
tickCh = make(chan time.Time)
|
||||
client = coderdtest.New(t, &coderdtest.Options{
|
||||
AutobuildTicker: tickCh,
|
||||
@ -199,20 +190,11 @@ func TestExecutorAutostopOK(t *testing.T) {
|
||||
})
|
||||
// Given: we have a user with a workspace
|
||||
workspace = mustProvisionWorkspace(t, client)
|
||||
ttl = time.Minute
|
||||
ttl = *workspace.TTL
|
||||
)
|
||||
// Given: workspace is running
|
||||
require.Equal(t, codersdk.WorkspaceTransitionStart, workspace.LatestBuild.Transition)
|
||||
|
||||
// Given: the workspace initially has autostop disabled
|
||||
require.Nil(t, workspace.TTL)
|
||||
|
||||
// When: we enable workspace autostop
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
|
||||
TTL: &ttl,
|
||||
}))
|
||||
|
||||
// When: the autobuild executor ticks *after* the TTL:
|
||||
go func() {
|
||||
tickCh <- time.Now().UTC().Add(ttl + time.Minute)
|
||||
@ -231,41 +213,32 @@ func TestExecutorAutostopAlreadyStopped(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
err error
|
||||
tickCh = make(chan time.Time)
|
||||
client = coderdtest.New(t, &coderdtest.Options{
|
||||
AutobuildTicker: tickCh,
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
// Given: we have a user with a workspace
|
||||
workspace = mustProvisionWorkspace(t, client)
|
||||
ttl = time.Minute
|
||||
// Given: we have a user with a workspace (disabling autostart)
|
||||
workspace = mustProvisionWorkspace(t, client, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.AutostartSchedule = nil
|
||||
})
|
||||
ttl = *workspace.TTL
|
||||
)
|
||||
|
||||
// Given: workspace is stopped
|
||||
workspace = mustTransitionWorkspace(t, client, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Given: the workspace initially has autostop disabled
|
||||
require.Nil(t, workspace.TTL)
|
||||
|
||||
// When: we set the TTL on the workspace
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
|
||||
TTL: &ttl,
|
||||
}))
|
||||
|
||||
// When: the autobuild executor ticks past the TTL
|
||||
go func() {
|
||||
tickCh <- time.Now().UTC().Add(ttl)
|
||||
tickCh <- time.Now().UTC().Add(ttl + time.Minute)
|
||||
close(tickCh)
|
||||
}()
|
||||
|
||||
// Then: the workspace should not be stopped.
|
||||
<-time.After(5 * time.Second)
|
||||
ws := mustWorkspace(t, client, workspace.ID)
|
||||
require.Equal(t, workspace.LatestBuild.ID, ws.LatestBuild.ID, "expected no further workspace builds to occur")
|
||||
require.Equal(t, codersdk.WorkspaceTransitionStop, ws.LatestBuild.Transition, "expected workspace not to be running")
|
||||
require.Equal(t, workspace.LatestBuild.ID, ws.LatestBuild.ID, "expected no further workspace builds to occur")
|
||||
}
|
||||
|
||||
func TestExecutorAutostopNotEnabled(t *testing.T) {
|
||||
@ -277,17 +250,19 @@ func TestExecutorAutostopNotEnabled(t *testing.T) {
|
||||
AutobuildTicker: tickCh,
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
// Given: we have a user with a workspace
|
||||
workspace = mustProvisionWorkspace(t, client)
|
||||
// Given: we have a user with a workspace that has no TTL set
|
||||
workspace = mustProvisionWorkspace(t, client, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.TTL = nil
|
||||
})
|
||||
)
|
||||
|
||||
// Given: workspace has no TTL set
|
||||
require.Nil(t, workspace.TTL)
|
||||
|
||||
// Given: workspace is running
|
||||
require.Equal(t, codersdk.WorkspaceTransitionStart, workspace.LatestBuild.Transition)
|
||||
|
||||
// Given: the workspace has autostop disabled
|
||||
require.Empty(t, workspace.TTL)
|
||||
|
||||
// When: the autobuild executor ticks
|
||||
// When: the autobuild executor ticks past the TTL
|
||||
go func() {
|
||||
tickCh <- time.Now().UTC().Add(time.Minute)
|
||||
close(tickCh)
|
||||
@ -315,9 +290,6 @@ func TestExecutorWorkspaceDeleted(t *testing.T) {
|
||||
workspace = mustProvisionWorkspace(t, client)
|
||||
)
|
||||
|
||||
// Given: the workspace initially has autostart disabled
|
||||
require.Empty(t, workspace.AutostartSchedule)
|
||||
|
||||
// When: we enable workspace autostart
|
||||
sched, err := schedule.Weekly("* * * * *")
|
||||
require.NoError(t, err)
|
||||
@ -352,16 +324,15 @@ func TestExecutorWorkspaceAutostartTooEarly(t *testing.T) {
|
||||
AutobuildTicker: tickCh,
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
// Given: we have a user with a workspace
|
||||
workspace = mustProvisionWorkspace(t, client)
|
||||
futureTime = time.Now().Add(time.Hour)
|
||||
futureTimeCron = fmt.Sprintf("%d %d * * *", futureTime.Minute(), futureTime.Hour())
|
||||
// Given: we have a user with a workspace configured to autostart some time in the future
|
||||
workspace = mustProvisionWorkspace(t, client, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.AutostartSchedule = &futureTimeCron
|
||||
})
|
||||
)
|
||||
|
||||
// Given: the workspace initially has autostart disabled
|
||||
require.Empty(t, workspace.AutostartSchedule)
|
||||
|
||||
// When: we enable workspace autostart with some time in the future
|
||||
futureTime := time.Now().Add(time.Hour)
|
||||
futureTimeCron := fmt.Sprintf("%d %d * * *", futureTime.Minute(), futureTime.Hour())
|
||||
sched, err := schedule.Weekly(futureTimeCron)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
|
||||
@ -385,7 +356,6 @@ func TestExecutorWorkspaceTTLTooEarly(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
tickCh = make(chan time.Time)
|
||||
client = coderdtest.New(t, &coderdtest.Options{
|
||||
AutobuildTicker: tickCh,
|
||||
@ -393,18 +363,9 @@ func TestExecutorWorkspaceTTLTooEarly(t *testing.T) {
|
||||
})
|
||||
// Given: we have a user with a workspace
|
||||
workspace = mustProvisionWorkspace(t, client)
|
||||
ttl = time.Hour
|
||||
)
|
||||
|
||||
// Given: the workspace initially has TTL unset
|
||||
require.Nil(t, workspace.TTL)
|
||||
|
||||
// When: we set the TTL to some time in the distant future
|
||||
require.NoError(t, client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
|
||||
TTL: &ttl,
|
||||
}))
|
||||
|
||||
// When: the autobuild executor ticks
|
||||
// When: the autobuild executor ticks before the TTL
|
||||
go func() {
|
||||
tickCh <- time.Now().UTC()
|
||||
close(tickCh)
|
||||
@ -434,24 +395,15 @@ func TestExecutorAutostartMultipleOK(t *testing.T) {
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
_ = coderdtest.New(t, &coderdtest.Options{
|
||||
AutobuildTicker: tickCh2,
|
||||
AutobuildTicker: tickCh2,
|
||||
IncludeProvisionerD: true,
|
||||
})
|
||||
// Given: we have a user with a workspace
|
||||
// Given: we have a user with a workspace that has autostart enabled (default)
|
||||
workspace = mustProvisionWorkspace(t, client)
|
||||
)
|
||||
// Given: workspace is stopped
|
||||
workspace = mustTransitionWorkspace(t, client, workspace.ID, database.WorkspaceTransitionStart, database.WorkspaceTransitionStop)
|
||||
|
||||
// Given: the workspace initially has autostart disabled
|
||||
require.Empty(t, workspace.AutostartSchedule)
|
||||
|
||||
// When: we enable workspace autostart
|
||||
sched, err := schedule.Weekly("* * * * *")
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, client.UpdateWorkspaceAutostart(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostartRequest{
|
||||
Schedule: sched.String(),
|
||||
}))
|
||||
|
||||
// When: the autobuild executor ticks
|
||||
go func() {
|
||||
tickCh <- time.Now().UTC().Add(time.Minute)
|
||||
@ -479,13 +431,13 @@ func TestExecutorAutostartMultipleOK(t *testing.T) {
|
||||
require.True(t, builds[1].CreatedAt.After(builds[2].CreatedAt))
|
||||
}
|
||||
|
||||
func mustProvisionWorkspace(t *testing.T, client *codersdk.Client) codersdk.Workspace {
|
||||
func mustProvisionWorkspace(t *testing.T, client *codersdk.Client, mut ...func(*codersdk.CreateWorkspaceRequest)) codersdk.Workspace {
|
||||
t.Helper()
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
|
||||
ws := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, mut...)
|
||||
coderdtest.AwaitWorkspaceBuildJob(t, client, ws.LatestBuild.ID)
|
||||
return mustWorkspace(t, client, ws.ID)
|
||||
}
|
||||
|
Reference in New Issue
Block a user