Thanks to visit codestin.com
Credit goes to github.com

Skip to content
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
4 changes: 2 additions & 2 deletions coderd/aitasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ func (api *API) convertTasks(ctx context.Context, requesterID uuid.UUID, dbTasks
}

// Gather associated data and convert to API workspaces.
data, err := api.workspaceData(ctx, workspaces)
data, err := api.workspaceData(ctx, workspaces, allWorkspaceRelated())
if err != nil {
return nil, xerrors.Errorf("fetch workspace data: %w", err)
}
Expand Down Expand Up @@ -547,7 +547,7 @@ func (api *API) taskGet(rw http.ResponseWriter, r *http.Request) {
return
}

data, err := api.workspaceData(ctx, []database.Workspace{workspace})
data, err := api.workspaceData(ctx, []database.Workspace{workspace}, allWorkspaceRelated())
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching workspace resources.",
Expand Down
169 changes: 108 additions & 61 deletions coderd/workspacebuilds.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (api *API) workspaceBuild(rw http.ResponseWriter, r *http.Request) {
workspaceBuild := httpmw.WorkspaceBuildParam(r)
workspace := httpmw.WorkspaceParam(r)

data, err := api.workspaceBuildsData(ctx, []database.WorkspaceBuild{workspaceBuild})
data, err := api.workspaceBuildsData(ctx, []database.WorkspaceBuild{workspaceBuild}, allLatestBuildRelated())
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error getting workspace build data.",
Expand Down Expand Up @@ -190,7 +190,7 @@ func (api *API) workspaceBuilds(rw http.ResponseWriter, r *http.Request) {
return
}

data, err := api.workspaceBuildsData(ctx, workspaceBuilds)
data, err := api.workspaceBuildsData(ctx, workspaceBuilds, allLatestBuildRelated())
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error getting workspace build data.",
Expand Down Expand Up @@ -281,7 +281,7 @@ func (api *API) workspaceBuildByBuildNumber(rw http.ResponseWriter, r *http.Requ
return
}

data, err := api.workspaceBuildsData(ctx, []database.WorkspaceBuild{workspaceBuild})
data, err := api.workspaceBuildsData(ctx, []database.WorkspaceBuild{workspaceBuild}, allLatestBuildRelated())
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error getting workspace build data.",
Expand Down Expand Up @@ -1110,39 +1110,59 @@ type workspaceBuildsData struct {
provisionerDaemons []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow
}

func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []database.WorkspaceBuild) (workspaceBuildsData, error) {
func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []database.WorkspaceBuild, cfg latestBuildRelated) (workspaceBuildsData, error) {
jobIDs := make([]uuid.UUID, 0, len(workspaceBuilds))
for _, build := range workspaceBuilds {
jobIDs = append(jobIDs, build.JobID)
}
jobs, err := api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, database.GetProvisionerJobsByIDsWithQueuePositionParams{
IDs: jobIDs,
StaleIntervalMS: provisionerdserver.StaleInterval.Milliseconds(),
})
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get provisioner jobs: %w", err)
}
pendingJobIDs := []uuid.UUID{}
for _, job := range jobs {
if job.ProvisionerJob.JobStatus == database.ProvisionerJobStatusPending {
pendingJobIDs = append(pendingJobIDs, job.ProvisionerJob.ID)

var (
jobs []database.GetProvisionerJobsByIDsWithQueuePositionRow
pendingJobProvisioners []database.GetEligibleProvisionerDaemonsByProvisionerJobIDsRow
)
if cfg.Job != nil {
var err error
jobs, err = api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, database.GetProvisionerJobsByIDsWithQueuePositionParams{
IDs: jobIDs,
StaleIntervalMS: provisionerdserver.StaleInterval.Milliseconds(),
})
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get provisioner jobs: %w", err)
}
pendingJobIDs := []uuid.UUID{}
for _, job := range jobs {
if job.ProvisionerJob.JobStatus == database.ProvisionerJobStatusPending {
pendingJobIDs = append(pendingJobIDs, job.ProvisionerJob.ID)
}
}
}

pendingJobProvisioners, err := api.Database.GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx, pendingJobIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get provisioner daemons: %w", err)
pendingJobProvisioners, err = api.Database.GetEligibleProvisionerDaemonsByProvisionerJobIDs(ctx, pendingJobIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get provisioner daemons: %w", err)
}
}

templateVersionIDs := make([]uuid.UUID, 0, len(workspaceBuilds))
for _, build := range workspaceBuilds {
templateVersionIDs = append(templateVersionIDs, build.TemplateVersionID)
var templateVersions []database.TemplateVersion
if cfg.TemplateVersion {
templateVersionIDs := make([]uuid.UUID, 0, len(workspaceBuilds))
for _, build := range workspaceBuilds {
templateVersionIDs = append(templateVersionIDs, build.TemplateVersionID)
}

var err error
// nolint:gocritic // Getting template versions by ID is a system function.
templateVersions, err = api.Database.GetTemplateVersionsByIDs(dbauthz.AsSystemRestricted(ctx), templateVersionIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get template versions: %w", err)
}
}

// nolint:gocritic // Getting template versions by ID is a system function.
templateVersions, err := api.Database.GetTemplateVersionsByIDs(dbauthz.AsSystemRestricted(ctx), templateVersionIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get template versions: %w", err)
if cfg.Resources == nil {
return workspaceBuildsData{
jobs: jobs,
templateVersions: templateVersions,
provisionerDaemons: pendingJobProvisioners,
}, nil
}

// nolint:gocritic // Getting workspace resources by job ID is a system function.
Expand All @@ -1164,19 +1184,36 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []datab
resourceIDs = append(resourceIDs, resource.ID)
}

// nolint:gocritic // Getting workspace resource metadata by resource ID is a system function.
metadata, err := api.Database.GetWorkspaceResourceMetadataByResourceIDs(dbauthz.AsSystemRestricted(ctx), resourceIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("fetching resource metadata: %w", err)
var (
metadata []database.WorkspaceResourceMetadatum
agents []database.WorkspaceAgent
egRes errgroup.Group
)
if cfg.Resources.Metadata {
egRes.Go(func() (err error) {
// nolint:gocritic // Getting workspace resource metadata by resource ID is a system function.
metadata, err = api.Database.GetWorkspaceResourceMetadataByResourceIDs(dbauthz.AsSystemRestricted(ctx), resourceIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return xerrors.Errorf("fetching resource metadata: %w", err)
}
return nil
})
}

// nolint:gocritic // Getting workspace agents by resource IDs is a system function.
agents, err := api.Database.GetWorkspaceAgentsByResourceIDs(dbauthz.AsSystemRestricted(ctx), resourceIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get workspace agents: %w", err)
if cfg.Resources.Agents != nil {
egRes.Go(func() (err error) {
// nolint:gocritic // Getting workspace agents by resource IDs is a system function.
agents, err = api.Database.GetWorkspaceAgentsByResourceIDs(dbauthz.AsSystemRestricted(ctx), resourceIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return xerrors.Errorf("get workspace agents: %w", err)
}
return nil
})
}
if err := egRes.Wait(); err != nil {
return workspaceBuildsData{}, err
}

if len(resources) == 0 {
if cfg.Resources.Agents == nil || len(agents) == 0 {
return workspaceBuildsData{
jobs: jobs,
templateVersions: templateVersions,
Expand All @@ -1185,6 +1222,7 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []datab
provisionerDaemons: pendingJobProvisioners,
}, nil
}
agentsCfg := cfg.Resources.Agents

agentIDs := make([]uuid.UUID, 0)
for _, agent := range agents {
Expand All @@ -1198,35 +1236,44 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaceBuilds []datab
)

var eg errgroup.Group
eg.Go(func() (err error) {
// nolint:gocritic // Getting workspace apps by agent IDs is a system function.
apps, err = api.Database.GetWorkspaceAppsByAgentIDs(dbauthz.AsSystemRestricted(ctx), agentIDs)
return err
})
eg.Go(func() (err error) {
// nolint:gocritic // Getting workspace scripts by agent IDs is a system function.
scripts, err = api.Database.GetWorkspaceAgentScriptsByAgentIDs(dbauthz.AsSystemRestricted(ctx), agentIDs)
return err
})
eg.Go(func() error {
// nolint:gocritic // Getting workspace agent log sources by agent IDs is a system function.
logSources, err = api.Database.GetWorkspaceAgentLogSourcesByAgentIDs(dbauthz.AsSystemRestricted(ctx), agentIDs)
return err
})
err = eg.Wait()
if err != nil {
if agentsCfg.Apps != nil {
eg.Go(func() (err error) {
// nolint:gocritic // Getting workspace apps by agent IDs is a system function.
apps, err = api.Database.GetWorkspaceAppsByAgentIDs(dbauthz.AsSystemRestricted(ctx), agentIDs)
return err
})
}
if agentsCfg.Scripts {
eg.Go(func() (err error) {
// nolint:gocritic // Getting workspace scripts by agent IDs is a system function.
scripts, err = api.Database.GetWorkspaceAgentScriptsByAgentIDs(dbauthz.AsSystemRestricted(ctx), agentIDs)
return err
})
}
if agentsCfg.LogSources {
eg.Go(func() error {
var err error
// nolint:gocritic // Getting workspace agent log sources by agent IDs is a system function.
logSources, err = api.Database.GetWorkspaceAgentLogSourcesByAgentIDs(dbauthz.AsSystemRestricted(ctx), agentIDs)
return err
})
}
if err := eg.Wait(); err != nil {
return workspaceBuildsData{}, err
}

appIDs := make([]uuid.UUID, 0)
for _, app := range apps {
appIDs = append(appIDs, app.ID)
}
var statuses []database.WorkspaceAppStatus
if cfg.appStatuses() {
appIDs := make([]uuid.UUID, 0)
for _, app := range apps {
appIDs = append(appIDs, app.ID)
}

// nolint:gocritic // Getting workspace app statuses by app IDs is a system function.
statuses, err := api.Database.GetWorkspaceAppStatusesByAppIDs(dbauthz.AsSystemRestricted(ctx), appIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get workspace app statuses: %w", err)
// nolint:gocritic // Getting workspace app statuses by app IDs is a system function.
statuses, err = api.Database.GetWorkspaceAppStatusesByAppIDs(dbauthz.AsSystemRestricted(ctx), appIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return workspaceBuildsData{}, xerrors.Errorf("get workspace app statuses: %w", err)
}
}

return workspaceBuildsData{
Expand Down
79 changes: 44 additions & 35 deletions coderd/workspaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (api *API) workspace(rw http.ResponseWriter, r *http.Request) {
return
}

data, err := api.workspaceData(ctx, []database.Workspace{workspace})
data, err := api.workspaceData(ctx, []database.Workspace{workspace}, allWorkspaceRelated())
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching workspace resources.",
Expand Down Expand Up @@ -224,7 +224,7 @@ func (api *API) workspaces(rw http.ResponseWriter, r *http.Request) {
return
}

data, err := api.workspaceData(ctx, workspaces)
data, err := api.workspaceData(ctx, workspaces, allWorkspaceRelated())
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching workspace resources.",
Expand Down Expand Up @@ -313,7 +313,7 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
return
}

data, err := api.workspaceData(ctx, []database.Workspace{workspace})
data, err := api.workspaceData(ctx, []database.Workspace{workspace}, allWorkspaceRelated())
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching workspace resources.",
Expand Down Expand Up @@ -1562,7 +1562,7 @@ func (api *API) putWorkspaceDormant(rw http.ResponseWriter, r *http.Request) {
return
}

data, err := api.workspaceData(ctx, []database.Workspace{workspace})
data, err := api.workspaceData(ctx, []database.Workspace{workspace}, allWorkspaceRelated())
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching workspace resources.",
Expand Down Expand Up @@ -2140,7 +2140,7 @@ func (api *API) watchWorkspace(
return
}

data, err := api.workspaceData(ctx, []database.Workspace{workspace})
data, err := api.workspaceData(ctx, []database.Workspace{workspace}, allWorkspaceRelated())
if err != nil {
_ = sendEvent(codersdk.ServerSentEvent{
Type: codersdk.ServerSentEventTypeError,
Expand Down Expand Up @@ -2678,7 +2678,7 @@ func (api *API) allowWorkspaceSharing(ctx context.Context, rw http.ResponseWrite
// does not have the correct perms to read a given template, the template will
// not be returned.
// So the caller must check the templates & users exist before using them.
func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspace) (workspaceData, error) {
func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspace, cfg workspaceRelated) (workspaceData, error) {
workspaceIDs := make([]uuid.UUID, 0, len(workspaces))
templateIDs := make([]uuid.UUID, 0, len(workspaces))
for _, workspace := range workspaces {
Expand All @@ -2692,41 +2692,50 @@ func (api *API) workspaceData(ctx context.Context, workspaces []database.Workspa
appStatuses []database.WorkspaceAppStatus
eg errgroup.Group
)
eg.Go(func() (err error) {
templates, err = api.Database.GetTemplatesWithFilter(ctx, database.GetTemplatesWithFilterParams{
IDs: templateIDs,
if cfg.Template {
eg.Go(func() (err error) {
templates, err = api.Database.GetTemplatesWithFilter(ctx, database.GetTemplatesWithFilterParams{
IDs: templateIDs,
})
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return xerrors.Errorf("get templates: %w", err)
}
return nil
})
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return xerrors.Errorf("get templates: %w", err)
}
return nil
})
eg.Go(func() (err error) {
// This query must be run as system restricted to be efficient.
// nolint:gocritic
builds, err = api.Database.GetLatestWorkspaceBuildsByWorkspaceIDs(dbauthz.AsSystemRestricted(ctx), workspaceIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return xerrors.Errorf("get workspace builds: %w", err)
}
return nil
})
eg.Go(func() (err error) {
// This query must be run as system restricted to be efficient.
// nolint:gocritic
appStatuses, err = api.Database.GetLatestWorkspaceAppStatusesByWorkspaceIDs(dbauthz.AsSystemRestricted(ctx), workspaceIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return xerrors.Errorf("get workspace app statuses: %w", err)
}
return nil
})
}
if cfg.LatestBuild != nil {
eg.Go(func() (err error) {
// This query must be run as system restricted to be efficient.
// nolint:gocritic
builds, err = api.Database.GetLatestWorkspaceBuildsByWorkspaceIDs(dbauthz.AsSystemRestricted(ctx), workspaceIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return xerrors.Errorf("get workspace builds: %w", err)
}
return nil
})
}
if cfg.LatestBuild.appStatuses() {
eg.Go(func() (err error) {
// This query must be run as system restricted to be efficient.
// nolint:gocritic
appStatuses, err = api.Database.GetLatestWorkspaceAppStatusesByWorkspaceIDs(dbauthz.AsSystemRestricted(ctx), workspaceIDs)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return xerrors.Errorf("get workspace app statuses: %w", err)
}
return nil
})
}
err := eg.Wait()
if err != nil {
return workspaceData{}, err
}

data, err := api.workspaceBuildsData(ctx, builds)
if err != nil {
return workspaceData{}, xerrors.Errorf("get workspace builds data: %w", err)
var data workspaceBuildsData
if cfg.LatestBuild != nil {
data, err = api.workspaceBuildsData(ctx, builds, *cfg.LatestBuild)
if err != nil {
return workspaceData{}, xerrors.Errorf("get workspace builds data: %w", err)
}
}

apiBuilds, err := api.convertWorkspaceBuilds(
Expand Down
Loading
Loading