mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor: workspace autostop_schedule -> ttl (#1578)
Co-authored-by: G r e y <grey@coder.com>
This commit is contained in:
-167
@@ -1,167 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/coder/coder/coderd/autobuild/schedule"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
const autostopDescriptionLong = `To have your workspace stop automatically at a regular time you can enable autostop.
|
||||
When enabling autostop, provide the minute, hour, and day(s) of week.
|
||||
The default autostop schedule is at 18:00 in your local timezone (TZ env, UTC by default).
|
||||
`
|
||||
|
||||
func autostop() *cobra.Command {
|
||||
autostopCmd := &cobra.Command{
|
||||
Annotations: workspaceCommand,
|
||||
Use: "autostop enable <workspace>",
|
||||
Short: "schedule a workspace to automatically stop at a regular time",
|
||||
Long: autostopDescriptionLong,
|
||||
Example: "coder autostop enable my-workspace --minute 0 --hour 18 --days 1-5 -tz Europe/Dublin",
|
||||
}
|
||||
|
||||
autostopCmd.AddCommand(autostopShow())
|
||||
autostopCmd.AddCommand(autostopEnable())
|
||||
autostopCmd.AddCommand(autostopDisable())
|
||||
|
||||
return autostopCmd
|
||||
}
|
||||
|
||||
func autostopShow() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "show <workspace_name>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := createClient(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
organization, err := currentOrganization(cmd, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if workspace.AutostopSchedule == "" {
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "not enabled\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
validSchedule, err := schedule.Weekly(workspace.AutostopSchedule)
|
||||
if err != nil {
|
||||
// This should never happen.
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "invalid autostop schedule %q for workspace %s: %s\n", workspace.AutostopSchedule, workspace.Name, err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
next := validSchedule.Next(time.Now())
|
||||
loc, _ := time.LoadLocation(validSchedule.Timezone())
|
||||
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(),
|
||||
"schedule: %s\ntimezone: %s\nnext: %s\n",
|
||||
validSchedule.Cron(),
|
||||
validSchedule.Timezone(),
|
||||
next.In(loc),
|
||||
)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func autostopEnable() *cobra.Command {
|
||||
// yes some of these are technically numbers but the cron library will do that work
|
||||
var autostopMinute string
|
||||
var autostopHour string
|
||||
var autostopDayOfWeek string
|
||||
var autostopTimezone string
|
||||
cmd := &cobra.Command{
|
||||
Use: "enable <workspace_name> <schedule>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := createClient(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
organization, err := currentOrganization(cmd, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
spec := fmt.Sprintf("CRON_TZ=%s %s %s * * %s", autostopTimezone, autostopMinute, autostopHour, autostopDayOfWeek)
|
||||
validSchedule, err := schedule.Weekly(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = client.UpdateWorkspaceAutostop(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceAutostopRequest{
|
||||
Schedule: validSchedule.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "\nThe %s workspace will automatically stop at %s.\n\n", workspace.Name, validSchedule.Next(time.Now()))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVar(&autostopMinute, "minute", "0", "autostop minute")
|
||||
cmd.Flags().StringVar(&autostopHour, "hour", "18", "autostop hour")
|
||||
cmd.Flags().StringVar(&autostopDayOfWeek, "days", "1-5", "autostop day(s) of week")
|
||||
tzEnv := os.Getenv("TZ")
|
||||
if tzEnv == "" {
|
||||
tzEnv = "UTC"
|
||||
}
|
||||
cmd.Flags().StringVar(&autostopTimezone, "tz", tzEnv, "autostop timezone")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func autostopDisable() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "disable <workspace_name>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := createClient(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
organization, err := currentOrganization(cmd, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = client.UpdateWorkspaceAutostop(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceAutostopRequest{
|
||||
Schedule: "",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "\nThe %s workspace will no longer automatically stop.\n\n", workspace.Name)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
+3
-5
@@ -49,7 +49,7 @@ func list() *cobra.Command {
|
||||
}
|
||||
|
||||
tableWriter := cliui.Table()
|
||||
header := table.Row{"workspace", "template", "status", "last built", "outdated", "autostart", "autostop"}
|
||||
header := table.Row{"workspace", "template", "status", "last built", "outdated", "autostart", "ttl"}
|
||||
tableWriter.AppendHeader(header)
|
||||
tableWriter.SortBy([]table.SortBy{{
|
||||
Name: "workspace",
|
||||
@@ -116,10 +116,8 @@ func list() *cobra.Command {
|
||||
}
|
||||
|
||||
autostopDisplay := "-"
|
||||
if workspace.AutostopSchedule != "" {
|
||||
if sched, err := schedule.Weekly(workspace.AutostopSchedule); err == nil {
|
||||
autostopDisplay = sched.Cron()
|
||||
}
|
||||
if workspace.TTL != nil {
|
||||
autostopDisplay = workspace.TTL.String()
|
||||
}
|
||||
|
||||
user := usersByID[workspace.OwnerID]
|
||||
|
||||
+1
-1
@@ -62,7 +62,6 @@ func Root() *cobra.Command {
|
||||
|
||||
cmd.AddCommand(
|
||||
autostart(),
|
||||
autostop(),
|
||||
configSSH(),
|
||||
create(),
|
||||
delete(),
|
||||
@@ -78,6 +77,7 @@ func Root() *cobra.Command {
|
||||
stop(),
|
||||
ssh(),
|
||||
templates(),
|
||||
ttl(),
|
||||
update(),
|
||||
users(),
|
||||
portForward(),
|
||||
|
||||
+2
-8
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/coder/coder/cli/cliflag"
|
||||
"github.com/coder/coder/cli/cliui"
|
||||
"github.com/coder/coder/coderd/autobuild/notify"
|
||||
"github.com/coder/coder/coderd/autobuild/schedule"
|
||||
"github.com/coder/coder/codersdk"
|
||||
"github.com/coder/coder/cryptorand"
|
||||
)
|
||||
@@ -270,16 +269,11 @@ func notifyCondition(ctx context.Context, client *codersdk.Client, workspaceID u
|
||||
return time.Time{}, nil
|
||||
}
|
||||
|
||||
if ws.AutostopSchedule == "" {
|
||||
if ws.TTL == nil || *ws.TTL == 0 {
|
||||
return time.Time{}, nil
|
||||
}
|
||||
|
||||
sched, err := schedule.Weekly(ws.AutostopSchedule)
|
||||
if err != nil {
|
||||
return time.Time{}, nil
|
||||
}
|
||||
|
||||
deadline = sched.Next(now)
|
||||
deadline = ws.LatestBuild.UpdatedAt.Add(*ws.TTL)
|
||||
callback = func() {
|
||||
ttl := deadline.Sub(now)
|
||||
var title, body string
|
||||
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
const ttlDescriptionLong = `To have your workspace stop automatically after a configurable interval has passed.
|
||||
Minimum TTL is 1 minute.
|
||||
`
|
||||
|
||||
func ttl() *cobra.Command {
|
||||
ttlCmd := &cobra.Command{
|
||||
Annotations: workspaceCommand,
|
||||
Use: "ttl [command]",
|
||||
Short: "Schedule a workspace to automatically stop after a configurable interval",
|
||||
Long: ttlDescriptionLong,
|
||||
Example: "coder ttl set my-workspace 8h30m",
|
||||
}
|
||||
|
||||
ttlCmd.AddCommand(ttlShow())
|
||||
ttlCmd.AddCommand(ttlset())
|
||||
ttlCmd.AddCommand(ttlunset())
|
||||
|
||||
return ttlCmd
|
||||
}
|
||||
|
||||
func ttlShow() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "show <workspace_name>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := createClient(cmd)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create client: %w", err)
|
||||
}
|
||||
organization, err := currentOrganization(cmd, client)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get current org: %w", err)
|
||||
}
|
||||
|
||||
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get workspace: %w", err)
|
||||
}
|
||||
|
||||
if workspace.TTL == nil {
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "not set\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", workspace.TTL)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ttlset() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "set <workspace_name> <ttl>",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := createClient(cmd)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create client: %w", err)
|
||||
}
|
||||
organization, err := currentOrganization(cmd, client)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get current org: %w", err)
|
||||
}
|
||||
|
||||
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get workspace: %w", err)
|
||||
}
|
||||
|
||||
ttl, err := time.ParseDuration(args[1])
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse ttl: %w", err)
|
||||
}
|
||||
|
||||
truncated := ttl.Truncate(time.Minute)
|
||||
|
||||
if truncated == 0 {
|
||||
return xerrors.Errorf("ttl must be at least 1m")
|
||||
}
|
||||
|
||||
if truncated != ttl {
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "warning: ttl rounded down to %s\n", truncated)
|
||||
}
|
||||
|
||||
err = client.UpdateWorkspaceTTL(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
|
||||
TTL: &truncated,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("update workspace ttl: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func ttlunset() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "unset <workspace_name>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client, err := createClient(cmd)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create client: %w", err)
|
||||
}
|
||||
organization, err := currentOrganization(cmd, client)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get current org: %w", err)
|
||||
}
|
||||
|
||||
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get workspace: %w", err)
|
||||
}
|
||||
|
||||
err = client.UpdateWorkspaceTTL(cmd.Context(), workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
|
||||
TTL: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("update workspace ttl: %w", err)
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprint(cmd.OutOrStdout(), "ttl unset\n", workspace.Name)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package cli_test
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
func TestAutostop(t *testing.T) {
|
||||
func TestTTL(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("ShowOK", func(t *testing.T) {
|
||||
@@ -29,13 +29,13 @@ func TestAutostop(t *testing.T) {
|
||||
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
|
||||
cmdArgs = []string{"autostop", "show", workspace.Name}
|
||||
sched = "CRON_TZ=Europe/Dublin 30 17 * * 1-5"
|
||||
cmdArgs = []string{"ttl", "show", workspace.Name}
|
||||
ttl = 8*time.Hour + 30*time.Minute + 30*time.Second
|
||||
stdoutBuf = &bytes.Buffer{}
|
||||
)
|
||||
|
||||
err := client.UpdateWorkspaceAutostop(ctx, workspace.ID, codersdk.UpdateWorkspaceAutostopRequest{
|
||||
Schedule: sched,
|
||||
err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
|
||||
TTL: &ttl,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -45,11 +45,10 @@ func TestAutostop(t *testing.T) {
|
||||
|
||||
err = cmd.Execute()
|
||||
require.NoError(t, err, "unexpected error")
|
||||
// CRON_TZ gets stripped
|
||||
require.Contains(t, stdoutBuf.String(), "schedule: 30 17 * * 1-5")
|
||||
require.Equal(t, ttl.Truncate(time.Minute).String(), strings.TrimSpace(stdoutBuf.String()))
|
||||
})
|
||||
|
||||
t.Run("EnableDisableOK", func(t *testing.T) {
|
||||
t.Run("SetUnsetOK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
@@ -61,8 +60,8 @@ func TestAutostop(t *testing.T) {
|
||||
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
|
||||
cmdArgs = []string{"autostop", "enable", workspace.Name, "--minute", "30", "--hour", "17", "--days", "1-5", "--tz", "Europe/Dublin"}
|
||||
sched = "CRON_TZ=Europe/Dublin 30 17 * * 1-5"
|
||||
ttl = 8*time.Hour + 30*time.Minute + 30*time.Second
|
||||
cmdArgs = []string{"ttl", "set", workspace.Name, ttl.String()}
|
||||
stdoutBuf = &bytes.Buffer{}
|
||||
)
|
||||
|
||||
@@ -72,65 +71,28 @@ func TestAutostop(t *testing.T) {
|
||||
|
||||
err := cmd.Execute()
|
||||
require.NoError(t, err, "unexpected error")
|
||||
require.Contains(t, stdoutBuf.String(), "will automatically stop at", "unexpected output")
|
||||
|
||||
// Ensure autostop schedule updated
|
||||
// Ensure ttl updated
|
||||
updated, err := client.Workspace(ctx, workspace.ID)
|
||||
require.NoError(t, err, "fetch updated workspace")
|
||||
require.Equal(t, sched, updated.AutostopSchedule, "expected autostop schedule to be set")
|
||||
require.Equal(t, ttl.Truncate(time.Minute), *updated.TTL)
|
||||
require.Contains(t, stdoutBuf.String(), "warning: ttl rounded down")
|
||||
|
||||
// Disable schedule
|
||||
cmd, root = clitest.New(t, "autostop", "disable", workspace.Name)
|
||||
// unset schedule
|
||||
cmd, root = clitest.New(t, "ttl", "unset", workspace.Name)
|
||||
clitest.SetupConfig(t, client, root)
|
||||
cmd.SetOut(stdoutBuf)
|
||||
|
||||
err = cmd.Execute()
|
||||
require.NoError(t, err, "unexpected error")
|
||||
require.Contains(t, stdoutBuf.String(), "will no longer automatically stop", "unexpected output")
|
||||
|
||||
// Ensure autostop schedule updated
|
||||
// Ensure ttl updated
|
||||
updated, err = client.Workspace(ctx, workspace.ID)
|
||||
require.NoError(t, err, "fetch updated workspace")
|
||||
require.Empty(t, updated.AutostopSchedule, "expected autostop schedule to not be set")
|
||||
require.Nil(t, updated.TTL, "expected ttl to not be set")
|
||||
})
|
||||
|
||||
t.Run("Enable_NotFound", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
client = coderdtest.New(t, nil)
|
||||
_ = coderdtest.NewProvisionerDaemon(t, client)
|
||||
user = coderdtest.CreateFirstUser(t, client)
|
||||
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
)
|
||||
|
||||
cmd, root := clitest.New(t, "autostop", "enable", "doesnotexist")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
|
||||
err := cmd.Execute()
|
||||
require.ErrorContains(t, err, "status code 403: forbidden", "unexpected error")
|
||||
})
|
||||
|
||||
t.Run("Disable_NotFound", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
client = coderdtest.New(t, nil)
|
||||
_ = coderdtest.NewProvisionerDaemon(t, client)
|
||||
user = coderdtest.CreateFirstUser(t, client)
|
||||
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
)
|
||||
|
||||
cmd, root := clitest.New(t, "autostop", "disable", "doesnotexist")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
|
||||
err := cmd.Execute()
|
||||
require.ErrorContains(t, err, "status code 403: forbidden", "unexpected error")
|
||||
})
|
||||
|
||||
t.Run("Enable_DefaultSchedule", func(t *testing.T) {
|
||||
t.Run("ZeroInvalid", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
@@ -142,24 +104,72 @@ func TestAutostop(t *testing.T) {
|
||||
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
|
||||
ttl = 8*time.Hour + 30*time.Minute + 30*time.Second
|
||||
cmdArgs = []string{"ttl", "set", workspace.Name, ttl.String()}
|
||||
stdoutBuf = &bytes.Buffer{}
|
||||
)
|
||||
|
||||
// check current TZ env var
|
||||
currTz := os.Getenv("TZ")
|
||||
if currTz == "" {
|
||||
currTz = "UTC"
|
||||
}
|
||||
expectedSchedule := fmt.Sprintf("CRON_TZ=%s 0 18 * * 1-5", currTz)
|
||||
|
||||
cmd, root := clitest.New(t, "autostop", "enable", workspace.Name)
|
||||
cmd, root := clitest.New(t, cmdArgs...)
|
||||
clitest.SetupConfig(t, client, root)
|
||||
cmd.SetOut(stdoutBuf)
|
||||
|
||||
err := cmd.Execute()
|
||||
require.NoError(t, err, "unexpected error")
|
||||
|
||||
// Ensure nothing happened
|
||||
// Ensure ttl updated
|
||||
updated, err := client.Workspace(ctx, workspace.ID)
|
||||
require.NoError(t, err, "fetch updated workspace")
|
||||
require.Equal(t, expectedSchedule, updated.AutostopSchedule, "expected default autostop schedule")
|
||||
require.Equal(t, ttl.Truncate(time.Minute), *updated.TTL)
|
||||
require.Contains(t, stdoutBuf.String(), "warning: ttl rounded down")
|
||||
|
||||
// A TTL of zero is not considered valid.
|
||||
stdoutBuf.Reset()
|
||||
cmd, root = clitest.New(t, "ttl", "set", workspace.Name, "0s")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
cmd.SetOut(stdoutBuf)
|
||||
|
||||
err = cmd.Execute()
|
||||
require.EqualError(t, err, "ttl must be at least 1m", "unexpected error")
|
||||
|
||||
// Ensure ttl remains as before
|
||||
updated, err = client.Workspace(ctx, workspace.ID)
|
||||
require.NoError(t, err, "fetch updated workspace")
|
||||
require.Equal(t, ttl.Truncate(time.Minute), *updated.TTL)
|
||||
})
|
||||
|
||||
t.Run("Set_NotFound", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
client = coderdtest.New(t, nil)
|
||||
_ = coderdtest.NewProvisionerDaemon(t, client)
|
||||
user = coderdtest.CreateFirstUser(t, client)
|
||||
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
)
|
||||
|
||||
cmd, root := clitest.New(t, "ttl", "set", "doesnotexist", "8h30m")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
|
||||
err := cmd.Execute()
|
||||
require.ErrorContains(t, err, "status code 403: forbidden", "unexpected error")
|
||||
})
|
||||
|
||||
t.Run("Unset_NotFound", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var (
|
||||
client = coderdtest.New(t, nil)
|
||||
_ = coderdtest.NewProvisionerDaemon(t, client)
|
||||
user = coderdtest.CreateFirstUser(t, client)
|
||||
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
||||
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
)
|
||||
|
||||
cmd, root := clitest.New(t, "ttl", "unset", "doesnotexist")
|
||||
clitest.SetupConfig(t, client, root)
|
||||
|
||||
err := cmd.Execute()
|
||||
require.ErrorContains(t, err, "status code 403: forbidden", "unexpected error")
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user