Skip to content

feat(cli/exp): extend scaletest create-workspaces with --retry option #11825

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions cli/exp_scaletest.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ func (r *RootCmd) scaletestCleanup() *clibase.Cmd {
func (r *RootCmd) scaletestCreateWorkspaces() *clibase.Cmd {
var (
count int64
retry int64
template string

noCleanup bool
Expand Down Expand Up @@ -644,6 +645,7 @@ func (r *RootCmd) scaletestCreateWorkspaces() *clibase.Cmd {
RichParameterValues: richParameters,
},
NoWaitForAgents: noWaitForAgents,
Retry: int(retry),
},
NoCleanup: noCleanup,
}
Expand Down Expand Up @@ -753,6 +755,13 @@ func (r *RootCmd) scaletestCreateWorkspaces() *clibase.Cmd {
Description: "Required: Number of workspaces to create.",
Value: clibase.Int64Of(&count),
},
{
Flag: "retry",
Env: "CODER_SCALETEST_RETRY",
Default: "0",
Description: "Number of tries to create and bring up the workspace.",
Value: clibase.Int64Of(&retry),
},
{
Flag: "template",
FlagShorthand: "t",
Expand Down
3 changes: 3 additions & 0 deletions scaletest/workspacebuild/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ type Config struct {
// NoWaitForAgents determines whether the test should wait for the workspace
// agents to connect before returning.
NoWaitForAgents bool `json:"no_wait_for_agents"`
// Retry determines how many times to retry starting a workspace build if it
// fails.
Retry int `json:"retry"`
}

func (c Config) Validate() error {
Expand Down
20 changes: 19 additions & 1 deletion scaletest/workspacebuild/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,25 @@ func (r *Runner) Run(ctx context.Context, _ string, logs io.Writer) error {

err = waitForBuild(ctx, logs, r.client, workspace.LatestBuild.ID)
if err != nil {
return xerrors.Errorf("wait for build: %w", err)
for i := 0; i < r.cfg.Retry; i++ {
_, _ = fmt.Fprintf(logs, "Retrying build %d/%d...\n", i+1, r.cfg.Retry)

workspace.LatestBuild, err = r.client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
Transition: codersdk.WorkspaceTransitionStart,
RichParameterValues: req.RichParameterValues,
TemplateVersionID: req.TemplateVersionID,
})
if err != nil {
return xerrors.Errorf("create workspace build: %w", err)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: We could simply retry here, but I think it's unlikely another attempt will work if we can't create builds at all.

}
err = waitForBuild(ctx, logs, r.client, workspace.LatestBuild.ID)
if err == nil {
break
}
}
if err != nil {
return xerrors.Errorf("wait for build: %w", err)
}
}

if r.cfg.NoWaitForAgents {
Expand Down
50 changes: 50 additions & 0 deletions scaletest/workspacebuild/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -230,4 +231,53 @@ func Test_Runner(t *testing.T) {
require.Error(t, err)
require.ErrorContains(t, err, "test error")
})

t.Run("RetryBuild", func(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
client := coderdtest.New(t, &coderdtest.Options{
IncludeProvisionerDaemon: true,
Logger: &logger,
})
user := coderdtest.CreateFirstUser(t, client)

version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionPlan: echo.PlanComplete,
ProvisionApply: []*proto.Response{
{
Type: &proto.Response_Apply{
Apply: &proto.ApplyComplete{
Error: "test error",
},
},
},
},
})

template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)

runner := workspacebuild.NewRunner(client, workspacebuild.Config{
OrganizationID: user.OrganizationID,
UserID: codersdk.Me,
Request: codersdk.CreateWorkspaceRequest{
TemplateID: template.ID,
},
Retry: 1,
})

logs := bytes.NewBuffer(nil)
err := runner.Run(ctx, "1", logs)
logsStr := logs.String()
t.Log("Runner logs:\n\n" + logsStr)
require.Error(t, err)
require.ErrorContains(t, err, "test error")
require.Equal(t, 1, strings.Count(logsStr, "Retrying build"))
require.Equal(t, 2*2, strings.Count(logsStr, "test error")) // once per error, once per logged sdk response.
})
}