mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
This PR adds fields to templates that constrain values for workspaces derived from that template. - Autostop: Adds a field max_ttl on the template which limits the maximum value of ttl on all workspaces derived from that template. Defaulting to 168 hours, enforced on edits to workspace metadata. New workspaces will default to the templates's `max_ttl` if not specified. - Autostart: Adds a field min_autostart_duration which limits the minimum duration between successive autostarts of a template, measured from a single reference time. Defaulting to 1 hour, enforced on edits to workspace metadata.
205 lines
7.2 KiB
Go
205 lines
7.2 KiB
Go
package cli_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/cli/clitest"
|
|
"github.com/coder/coder/coderd/coderdtest"
|
|
"github.com/coder/coder/coderd/util/ptr"
|
|
"github.com/coder/coder/codersdk"
|
|
)
|
|
|
|
func TestTTL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("ShowOK", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
ctx = context.Background()
|
|
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
|
|
user = coderdtest.CreateFirstUser(t, client)
|
|
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
_ = 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{"ttl", "show", workspace.Name}
|
|
ttl = 8*time.Hour + 30*time.Minute + 30*time.Second
|
|
stdoutBuf = &bytes.Buffer{}
|
|
)
|
|
|
|
err := client.UpdateWorkspaceTTL(ctx, workspace.ID, codersdk.UpdateWorkspaceTTLRequest{
|
|
TTLMillis: ptr.Ref(ttl.Milliseconds()),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
cmd, root := clitest.New(t, cmdArgs...)
|
|
clitest.SetupConfig(t, client, root)
|
|
cmd.SetOut(stdoutBuf)
|
|
|
|
err = cmd.Execute()
|
|
require.NoError(t, err, "unexpected error")
|
|
require.Equal(t, ttl.Truncate(time.Minute).String(), strings.TrimSpace(stdoutBuf.String()))
|
|
})
|
|
|
|
t.Run("SetUnsetOK", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
ctx = context.Background()
|
|
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
|
|
user = coderdtest.CreateFirstUser(t, client)
|
|
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
_ = 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{}
|
|
)
|
|
|
|
cmd, root := clitest.New(t, cmdArgs...)
|
|
clitest.SetupConfig(t, client, root)
|
|
cmd.SetOut(stdoutBuf)
|
|
|
|
err := cmd.Execute()
|
|
require.NoError(t, err, "unexpected error")
|
|
|
|
// Ensure ttl updated
|
|
updated, err := client.Workspace(ctx, workspace.ID)
|
|
require.NoError(t, err, "fetch updated workspace")
|
|
require.Equal(t, ttl.Truncate(time.Minute), time.Duration(*updated.TTLMillis)*time.Millisecond)
|
|
require.Contains(t, stdoutBuf.String(), "warning: ttl rounded down")
|
|
|
|
// 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")
|
|
|
|
// Ensure ttl updated
|
|
updated, err = client.Workspace(ctx, workspace.ID)
|
|
require.NoError(t, err, "fetch updated workspace")
|
|
require.Nil(t, updated.TTLMillis, "expected ttl to not be set")
|
|
})
|
|
|
|
t.Run("ZeroInvalid", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
ctx = context.Background()
|
|
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
|
|
user = coderdtest.CreateFirstUser(t, client)
|
|
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
_ = 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{}
|
|
)
|
|
|
|
cmd, root := clitest.New(t, cmdArgs...)
|
|
clitest.SetupConfig(t, client, root)
|
|
cmd.SetOut(stdoutBuf)
|
|
|
|
err := cmd.Execute()
|
|
require.NoError(t, err, "unexpected error")
|
|
|
|
// Ensure ttl updated
|
|
updated, err := client.Workspace(ctx, workspace.ID)
|
|
require.NoError(t, err, "fetch updated workspace")
|
|
require.Equal(t, ttl.Truncate(time.Minute), time.Duration(*updated.TTLMillis)*time.Millisecond)
|
|
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), time.Duration(*updated.TTLMillis)*time.Millisecond)
|
|
})
|
|
|
|
t.Run("Set_NotFound", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
|
|
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, &coderdtest.Options{IncludeProvisionerD: true})
|
|
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")
|
|
})
|
|
|
|
t.Run("TemplateMaxTTL", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
ctx = context.Background()
|
|
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
|
|
user = coderdtest.CreateFirstUser(t, client)
|
|
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
|
|
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
|
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
|
|
ctr.MaxTTLMillis = ptr.Ref((8 * time.Hour).Milliseconds())
|
|
})
|
|
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
|
|
cwr.TTLMillis = ptr.Ref((8 * time.Hour).Milliseconds())
|
|
})
|
|
cmdArgs = []string{"ttl", "set", workspace.Name, "24h"}
|
|
stdoutBuf = &bytes.Buffer{}
|
|
)
|
|
|
|
cmd, root := clitest.New(t, cmdArgs...)
|
|
clitest.SetupConfig(t, client, root)
|
|
cmd.SetOut(stdoutBuf)
|
|
|
|
err := cmd.Execute()
|
|
require.ErrorContains(t, err, "ttl_ms: ttl must be below template maximum 8h0m0s")
|
|
|
|
// Ensure ttl not updated
|
|
updated, err := client.Workspace(ctx, workspace.ID)
|
|
require.NoError(t, err, "fetch updated workspace")
|
|
require.NotNil(t, updated.TTLMillis)
|
|
require.Equal(t, (8 * time.Hour).Milliseconds(), *updated.TTLMillis)
|
|
})
|
|
}
|