feat: autostop workspaces owned by suspended users (#13790)

This commit is contained in:
Marcin Tojek
2024-07-04 13:35:41 +00:00
committed by GitHub
parent c2d44d16a3
commit 7c41f957de
5 changed files with 78 additions and 3 deletions
+7 -3
View File
@@ -316,7 +316,7 @@ func getNextTransition(
error,
) {
switch {
case isEligibleForAutostop(ws, latestBuild, latestJob, currentTick):
case isEligibleForAutostop(user, ws, latestBuild, latestJob, currentTick):
return database.WorkspaceTransitionStop, database.BuildReasonAutostop, nil
case isEligibleForAutostart(user, ws, latestBuild, latestJob, templateSchedule, currentTick):
return database.WorkspaceTransitionStart, database.BuildReasonAutostart, nil
@@ -376,8 +376,8 @@ func isEligibleForAutostart(user database.User, ws database.Workspace, build dat
return !currentTick.Before(nextTransition)
}
// isEligibleForAutostart returns true if the workspace should be autostopped.
func isEligibleForAutostop(ws database.Workspace, build database.WorkspaceBuild, job database.ProvisionerJob, currentTick time.Time) bool {
// isEligibleForAutostop returns true if the workspace should be autostopped.
func isEligibleForAutostop(user database.User, ws database.Workspace, build database.WorkspaceBuild, job database.ProvisionerJob, currentTick time.Time) bool {
if job.JobStatus == database.ProvisionerJobStatusFailed {
return false
}
@@ -387,6 +387,10 @@ func isEligibleForAutostop(ws database.Workspace, build database.WorkspaceBuild,
return false
}
if build.Transition == database.WorkspaceTransitionStart && user.Status == database.UserStatusSuspended {
return true
}
// A workspace must be started in order for it to be auto-stopped.
return build.Transition == database.WorkspaceTransitionStart &&
!build.Deadline.IsZero() &&
@@ -563,6 +563,52 @@ func TestExecutorWorkspaceAutostopBeforeDeadline(t *testing.T) {
assert.Len(t, stats.Transitions, 0)
}
func TestExecuteAutostopSuspendedUser(t *testing.T) {
t.Parallel()
var (
ctx = testutil.Context(t, testutil.WaitShort)
tickCh = make(chan time.Time)
statsCh = make(chan autobuild.Stats)
client = coderdtest.New(t, &coderdtest.Options{
AutobuildTicker: tickCh,
IncludeProvisionerDaemon: true,
AutobuildStats: statsCh,
})
)
admin := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, admin.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, admin.OrganizationID, version.ID)
userClient, user := coderdtest.CreateAnotherUser(t, client, admin.OrganizationID)
workspace := coderdtest.CreateWorkspace(t, userClient, admin.OrganizationID, template.ID)
coderdtest.AwaitWorkspaceBuildJobCompleted(t, userClient, workspace.LatestBuild.ID)
// Given: workspace is running, and the user is suspended.
workspace = coderdtest.MustWorkspace(t, userClient, workspace.ID)
require.Equal(t, codersdk.WorkspaceStatusRunning, workspace.LatestBuild.Status)
_, err := client.UpdateUserStatus(ctx, user.ID.String(), codersdk.UserStatusSuspended)
require.NoError(t, err, "update user status")
// When: the autobuild executor ticks after the scheduled time
go func() {
tickCh <- time.Unix(0, 0) // the exact time is not important
close(tickCh)
}()
// Then: the workspace should be stopped
stats := <-statsCh
assert.Len(t, stats.Errors, 0)
assert.Len(t, stats.Transitions, 1)
assert.Equal(t, stats.Transitions[workspace.ID], database.WorkspaceTransitionStop)
// Wait for stop to complete
workspace = coderdtest.MustWorkspace(t, client, workspace.ID)
workspaceBuild := coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
assert.Equal(t, codersdk.WorkspaceStatusStopped, workspaceBuild.Status)
}
func TestExecutorWorkspaceAutostopNoWaitChangedMyMind(t *testing.T) {
t.Parallel()