Skip to content
Closed
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
30 changes: 7 additions & 23 deletions cli/configssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,29 +474,13 @@ func (r *RootCmd) configSSH() *serpent.Command {

if configOptions.noWildcard {
// Fetch all workspaces to generate individual host entries.
var wsNames []string
offset := 0
const pageSize = 100
for {
res, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
Owner: codersdk.Me,
Offset: offset,
Limit: pageSize,
})
if err != nil {
return xerrors.Errorf("fetch workspaces: %w", err)
}
for _, ws := range res.Workspaces {
wsNames = append(wsNames, ws.Name)
}
// The endpoint applies its limit in SQL and then drops rows whose
// build or template the caller cannot read, so a page shorter than
// pageSize does not mean the result set is exhausted. Count is the
// total before the limit and offset are applied.
offset += pageSize
if offset >= res.Count {
break
}
workspaces, err := client.AllWorkspaces(ctx, codersdk.WorkspaceFilter{Owner: codersdk.Me})
if err != nil {
return xerrors.Errorf("fetch workspaces: %w", err)
}
wsNames := make([]string, 0, len(workspaces))
for _, ws := range workspaces {
wsNames = append(wsNames, ws.Name)
}
configOptions.workspaceNames = wsNames
}
Expand Down
81 changes: 25 additions & 56 deletions cli/exp_scaletest.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,6 @@ func (r *prebuildTemplateCleanupRunner) Run(ctx context.Context, _ string, _ io.
// caught in the cleanup. If template is non-empty only workspaces for that
// template are returned.
func getScaletestPrebuildWorkspaces(ctx context.Context, client *codersdk.Client, template string) ([]codersdk.Workspace, error) {
const pageSize = 100

templates, err := getScaletestPrebuildsTemplates(ctx, client, template)
if err != nil {
return nil, xerrors.Errorf("list scaletest prebuild templates: %w", err)
Expand All @@ -562,27 +560,16 @@ func getScaletestPrebuildWorkspaces(ctx context.Context, client *codersdk.Client
var result []codersdk.Workspace

for _, tmpl := range templates {
for page := 0; ; page++ {
resp, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
Template: tmpl.Name,
Offset: page * pageSize,
Limit: pageSize,
})
if err != nil {
return nil, xerrors.Errorf("list workspaces for template %q (page %d): %w", tmpl.Name, page, err)
}
for _, ws := range resp.Workspaces {
if _, ok := seen[ws.ID]; !ok {
seen[ws.ID] = struct{}{}
result = append(result, ws)
}
}
// The endpoint applies its limit in SQL and then drops rows whose build
// or template the caller cannot read, so a page shorter than pageSize
// does not mean the result set is exhausted. Count is the total before
// the limit and offset are applied.
if (page+1)*pageSize >= resp.Count {
break
workspaces, err := client.AllWorkspaces(ctx, codersdk.WorkspaceFilter{
Template: tmpl.Name,
})
if err != nil {
return nil, xerrors.Errorf("list workspaces for template %q: %w", tmpl.Name, err)
}
for _, ws := range workspaces {
if _, ok := seen[ws.ID]; !ok {
seen[ws.ID] = struct{}{}
result = append(result, ws)
}
}
}
Expand Down Expand Up @@ -2223,8 +2210,6 @@ func (r *runnableTraceWrapper) GetMetrics() map[string]any {

func getScaletestWorkspaces(ctx context.Context, client *codersdk.Client, owner, template string) ([]codersdk.Workspace, int, error) {
var (
pageNumber = 0
limit = 100
workspaces []codersdk.Workspace
skipped int
)
Expand All @@ -2240,40 +2225,24 @@ func getScaletestWorkspaces(ctx context.Context, client *codersdk.Client, owner,
}
noOwnerAccess := dv.Values != nil && dv.Values.DisableOwnerWorkspaceExec.Value()

for {
page, err := client.Workspaces(ctx, codersdk.WorkspaceFilter{
Name: "scaletest-",
Template: template,
Owner: owner,
Offset: pageNumber * limit,
Limit: limit,
})
if err != nil {
return nil, 0, xerrors.Errorf("fetch scaletest workspaces page %d: %w", pageNumber, err)
}

pageNumber++
all, err := client.AllWorkspaces(ctx, codersdk.WorkspaceFilter{
Name: "scaletest-",
Template: template,
Owner: owner,
})
if err != nil {
return nil, 0, xerrors.Errorf("fetch scaletest workspaces: %w", err)
}

pageWorkspaces := make([]codersdk.Workspace, 0, len(page.Workspaces))
for _, w := range page.Workspaces {
if !loadtestutil.IsScaleTestWorkspace(w.Name, w.OwnerName) {
continue
}
if noOwnerAccess && w.OwnerID != me.ID {
skipped++
continue
}
pageWorkspaces = append(pageWorkspaces, w)
for _, w := range all {
if !loadtestutil.IsScaleTestWorkspace(w.Name, w.OwnerName) {
continue
}
workspaces = append(workspaces, pageWorkspaces...)

// The endpoint applies its limit in SQL and then drops rows whose build or
// template the caller cannot read, so a short or empty page does not mean
// the result set is exhausted. Count is the total before the limit and
// offset are applied.
if pageNumber*limit >= page.Count {
break
if noOwnerAccess && w.OwnerID != me.ID {
skipped++
continue
}
workspaces = append(workspaces, w)
}
return workspaces, skipped, nil
}
Expand Down
6 changes: 3 additions & 3 deletions cli/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,12 @@ func (r *RootCmd) list() *serpent.Command {
// convert workspaces to scheduleListRow.
func QueryConvertWorkspaces[T any](ctx context.Context, client *codersdk.Client, filter codersdk.WorkspaceFilter, convertF func(time.Time, codersdk.Workspace) T) ([]T, error) {
var empty []T
workspaces, err := client.Workspaces(ctx, filter)
workspaces, err := client.AllWorkspaces(ctx, filter)
if err != nil {
return empty, xerrors.Errorf("query workspaces: %w", err)
}
converted := make([]T, len(workspaces.Workspaces))
for i, workspace := range workspaces.Workspaces {
converted := make([]T, len(workspaces))
for i, workspace := range workspaces {
converted[i] = convertF(time.Now(), workspace)
}
return converted, nil
Expand Down
4 changes: 2 additions & 2 deletions cli/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func (r *RootCmd) ssh() *serpent.Command {
return []string{}
}

res, err := client.Workspaces(inv.Context(), codersdk.WorkspaceFilter{
workspaces, err := client.AllWorkspaces(inv.Context(), codersdk.WorkspaceFilter{
Owner: codersdk.Me,
})
if err != nil {
Expand All @@ -181,7 +181,7 @@ func (r *RootCmd) ssh() *serpent.Command {
var mu sync.Mutex
var completions []string
var wg sync.WaitGroup
for _, ws := range res.Workspaces {
for _, ws := range workspaces {
wg.Add(1)
go func() {
defer wg.Done()
Expand Down
28 changes: 28 additions & 0 deletions codersdk/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,34 @@ func (c *Client) Workspaces(ctx context.Context, filter WorkspaceFilter) (Worksp
return wres, ReadBodyAsJSON(res, &wres)
}

// WorkspacePageSize is the number of rows AllWorkspaces requests per page.
const WorkspacePageSize = 100

// AllWorkspaces requests successive pages of workspaces matching the filter and
// returns every row. Limit and Offset on the filter are ignored.
//
// The offset advances by the requested page size rather than by the number of
// rows received. The endpoint applies its limit in SQL and then drops
// workspaces whose build or template the caller cannot read, so a page shorter
// than the page size does not mean the result set is exhausted. Count is the
// total before the limit and offset are applied.
func (c *Client) AllWorkspaces(ctx context.Context, filter WorkspaceFilter) ([]Workspace, error) {
filter.Limit = WorkspacePageSize
filter.Offset = 0
var all []Workspace
for {
page, err := c.Workspaces(ctx, filter)
if err != nil {
return nil, err
}
all = append(all, page.Workspaces...)
filter.Offset += WorkspacePageSize
if filter.Offset >= page.Count {
return all, nil
}
}
}

// WorkspaceByOwnerAndName returns a workspace by the owner's UUID and the workspace's name.
func (c *Client) WorkspaceByOwnerAndName(ctx context.Context, owner string, name string, params WorkspaceOptions) (Workspace, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/workspace/%s", owner, name), nil, func(r *http.Request) {
Expand Down
Loading
Loading