mirror of
https://github.com/coder/coder.git
synced 2026-06-04 05:28:20 +00:00
bddb808b25
Fixes all our Go file imports to match the preferred spec that we've _mostly_ been using. For example: ``` import ( "context" "time" "github.com/prometheus/client_golang/prometheus" "golang.org/x/xerrors" "gopkg.in/natefinch/lumberjack.v2" "cdr.dev/slog/v3" "github.com/coder/coder/v2/codersdk/agentsdk" "github.com/coder/serpent" ) ``` 3 groups: standard library, 3rd partly libs, Coder libs. This PR makes the change across the codebase. The PR in the stack above modifies our formatting to maintain this state of affairs, and is a separate PR so it's possible to review that one in detail.
176 lines
4.5 KiB
Go
176 lines
4.5 KiB
Go
package createworkspaces
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/sync/errgroup"
|
|
"golang.org/x/xerrors"
|
|
|
|
"cdr.dev/slog/v3"
|
|
"cdr.dev/slog/v3/sloggers/sloghuman"
|
|
"github.com/coder/coder/v2/coderd/tracing"
|
|
"github.com/coder/coder/v2/codersdk"
|
|
"github.com/coder/coder/v2/scaletest/agentconn"
|
|
"github.com/coder/coder/v2/scaletest/createusers"
|
|
"github.com/coder/coder/v2/scaletest/harness"
|
|
"github.com/coder/coder/v2/scaletest/loadtestutil"
|
|
"github.com/coder/coder/v2/scaletest/reconnectingpty"
|
|
"github.com/coder/coder/v2/scaletest/workspacebuild"
|
|
)
|
|
|
|
type Runner struct {
|
|
client *codersdk.Client
|
|
cfg Config
|
|
|
|
createUserRunner *createusers.Runner
|
|
workspacebuildRunner *workspacebuild.Runner
|
|
}
|
|
|
|
var (
|
|
_ harness.Runnable = &Runner{}
|
|
_ harness.Cleanable = &Runner{}
|
|
)
|
|
|
|
func NewRunner(client *codersdk.Client, cfg Config) *Runner {
|
|
return &Runner{
|
|
client: client,
|
|
cfg: cfg,
|
|
}
|
|
}
|
|
|
|
// Run implements Runnable.
|
|
func (r *Runner) Run(ctx context.Context, id string, logs io.Writer) error {
|
|
ctx, span := tracing.StartSpan(ctx)
|
|
defer span.End()
|
|
|
|
logs = loadtestutil.NewSyncWriter(logs)
|
|
logger := slog.Make(sloghuman.Sink(logs)).Leveled(slog.LevelDebug)
|
|
r.client.SetLogger(logger)
|
|
r.client.SetLogBodies(true)
|
|
|
|
var (
|
|
client = r.client
|
|
user codersdk.User
|
|
err error
|
|
)
|
|
if r.cfg.User.SessionToken != "" {
|
|
_, _ = fmt.Fprintln(logs, "Using existing user session token:")
|
|
user, err = client.User(ctx, "me")
|
|
if err != nil {
|
|
return xerrors.Errorf("generate random password for user: %w", err)
|
|
}
|
|
} else {
|
|
createUserConfig := createusers.Config{
|
|
OrganizationID: r.cfg.User.OrganizationID,
|
|
Username: r.cfg.User.Username,
|
|
Email: r.cfg.User.Email,
|
|
}
|
|
if err := createUserConfig.Validate(); err != nil {
|
|
return xerrors.Errorf("validate create user config: %w", err)
|
|
}
|
|
r.createUserRunner = createusers.NewRunner(r.client, createUserConfig)
|
|
newUser, err := r.createUserRunner.RunReturningUser(ctx, id, logs)
|
|
if err != nil {
|
|
return xerrors.Errorf("create user: %w", err)
|
|
}
|
|
user = newUser.User
|
|
client = codersdk.New(r.client.URL)
|
|
client.SetSessionToken(newUser.SessionToken)
|
|
}
|
|
|
|
_, _ = fmt.Fprintln(logs, "\nCreating workspace...")
|
|
workspaceBuildConfig := r.cfg.Workspace
|
|
workspaceBuildConfig.OrganizationID = r.cfg.User.OrganizationID
|
|
workspaceBuildConfig.UserID = user.ID.String()
|
|
r.workspacebuildRunner = workspacebuild.NewRunner(client, workspaceBuildConfig)
|
|
slimWorkspace, err := r.workspacebuildRunner.RunReturningWorkspace(ctx, id, logs)
|
|
if err != nil {
|
|
return xerrors.Errorf("create workspace: %w", err)
|
|
}
|
|
workspace, err := client.Workspace(ctx, slimWorkspace.ID)
|
|
if err != nil {
|
|
return xerrors.Errorf("get full workspace info: %w", err)
|
|
}
|
|
|
|
if r.cfg.Workspace.NoWaitForAgents {
|
|
return nil
|
|
}
|
|
|
|
// Find the first agent.
|
|
var agent codersdk.WorkspaceAgent
|
|
resourceLoop:
|
|
for _, res := range workspace.LatestBuild.Resources {
|
|
for _, a := range res.Agents {
|
|
agent = a
|
|
break resourceLoop
|
|
}
|
|
}
|
|
if agent.ID == uuid.Nil {
|
|
return xerrors.Errorf("no agents found for workspace %q", workspace.ID.String())
|
|
}
|
|
|
|
eg, egCtx := errgroup.WithContext(ctx)
|
|
if r.cfg.ReconnectingPTY != nil {
|
|
eg.Go(func() error {
|
|
reconnectingPTYConfig := *r.cfg.ReconnectingPTY
|
|
reconnectingPTYConfig.AgentID = agent.ID
|
|
|
|
reconnectingPTYRunner := reconnectingpty.NewRunner(client, reconnectingPTYConfig)
|
|
err := reconnectingPTYRunner.Run(egCtx, id, logs)
|
|
if err != nil {
|
|
return xerrors.Errorf("run reconnecting pty: %w", err)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
if r.cfg.AgentConn != nil {
|
|
eg.Go(func() error {
|
|
agentConnConfig := *r.cfg.AgentConn
|
|
agentConnConfig.AgentID = agent.ID
|
|
|
|
agentConnRunner := agentconn.NewRunner(client, agentConnConfig)
|
|
err := agentConnRunner.Run(egCtx, id, logs)
|
|
if err != nil {
|
|
return xerrors.Errorf("run agent connection: %w", err)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
err = eg.Wait()
|
|
if err != nil {
|
|
return xerrors.Errorf("run workspace connections in parallel: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Cleanup implements Cleanable.
|
|
func (r *Runner) Cleanup(ctx context.Context, id string, logs io.Writer) error {
|
|
if r.cfg.NoCleanup {
|
|
_, _ = fmt.Fprintln(logs, "skipping cleanup")
|
|
return nil
|
|
}
|
|
|
|
if r.workspacebuildRunner != nil {
|
|
err := r.workspacebuildRunner.Cleanup(ctx, id, logs)
|
|
if err != nil {
|
|
return xerrors.Errorf("cleanup workspace: %w", err)
|
|
}
|
|
}
|
|
|
|
if r.createUserRunner != nil {
|
|
err := r.createUserRunner.Cleanup(ctx, id, logs)
|
|
if err != nil {
|
|
return xerrors.Errorf("cleanup user: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|