feat(coderd): add endpoint to list provisioner jobs (#16029)

Closes #15190
Updates #15084
This commit is contained in:
Mathias Fredriksson
2025-01-20 11:18:53 +02:00
committed by GitHub
parent 0e8ef09415
commit 3864c7e3b0
33 changed files with 1599 additions and 209 deletions
+42
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
@@ -343,6 +344,47 @@ func (c *Client) OrganizationProvisionerDaemons(ctx context.Context, organizatio
return daemons, json.NewDecoder(res.Body).Decode(&daemons)
}
type OrganizationProvisionerJobsOptions struct {
Limit int
Status []ProvisionerJobStatus
}
func (c *Client) OrganizationProvisionerJobs(ctx context.Context, organizationID uuid.UUID, opts *OrganizationProvisionerJobsOptions) ([]ProvisionerJob, error) {
qp := url.Values{}
if opts != nil {
if opts.Limit > 0 {
qp.Add("limit", strconv.Itoa(opts.Limit))
}
if len(opts.Status) > 0 {
qp.Add("status", joinSlice(opts.Status))
}
}
res, err := c.Request(ctx, http.MethodGet,
fmt.Sprintf("/api/v2/organizations/%s/provisionerjobs?%s", organizationID.String(), qp.Encode()),
nil,
)
if err != nil {
return nil, xerrors.Errorf("make request: %w", err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, ReadBodyAsError(res)
}
var jobs []ProvisionerJob
return jobs, json.NewDecoder(res.Body).Decode(&jobs)
}
func joinSlice[T ~string](s []T) string {
var ss []string
for _, v := range s {
ss = append(ss, string(v))
}
return strings.Join(ss, ",")
}
// CreateTemplateVersion processes source-code and optionally associates the version with a template.
// Executing without a template is useful for validating source-code.
func (c *Client) CreateTemplateVersion(ctx context.Context, organizationID uuid.UUID, req CreateTemplateVersionRequest) (TemplateVersion, error) {
+45 -13
View File
@@ -112,6 +112,34 @@ const (
ProvisionerJobUnknown ProvisionerJobStatus = "unknown"
)
func ProvisionerJobStatusEnums() []ProvisionerJobStatus {
return []ProvisionerJobStatus{
ProvisionerJobPending,
ProvisionerJobRunning,
ProvisionerJobSucceeded,
ProvisionerJobCanceling,
ProvisionerJobCanceled,
ProvisionerJobFailed,
ProvisionerJobUnknown,
}
}
// ProvisionerJobInput represents the input for the job.
type ProvisionerJobInput struct {
TemplateVersionID *uuid.UUID `json:"template_version_id,omitempty" format:"uuid" table:"template version id"`
WorkspaceBuildID *uuid.UUID `json:"workspace_build_id,omitempty" format:"uuid" table:"workspace build id"`
Error string `json:"error,omitempty" table:"-"`
}
// ProvisionerJobType represents the type of job.
type ProvisionerJobType string
const (
ProvisionerJobTypeTemplateVersionImport ProvisionerJobType = "template_version_import"
ProvisionerJobTypeWorkspaceBuild ProvisionerJobType = "workspace_build"
ProvisionerJobTypeTemplateVersionDryRun ProvisionerJobType = "template_version_dry_run"
)
// JobErrorCode defines the error code returned by job runner.
type JobErrorCode string
@@ -127,19 +155,23 @@ func JobIsMissingParameterErrorCode(code JobErrorCode) bool {
// ProvisionerJob describes the job executed by the provisioning daemon.
type ProvisionerJob struct {
ID uuid.UUID `json:"id" format:"uuid"`
CreatedAt time.Time `json:"created_at" format:"date-time"`
StartedAt *time.Time `json:"started_at,omitempty" format:"date-time"`
CompletedAt *time.Time `json:"completed_at,omitempty" format:"date-time"`
CanceledAt *time.Time `json:"canceled_at,omitempty" format:"date-time"`
Error string `json:"error,omitempty"`
ErrorCode JobErrorCode `json:"error_code,omitempty" enums:"REQUIRED_TEMPLATE_VARIABLES"`
Status ProvisionerJobStatus `json:"status" enums:"pending,running,succeeded,canceling,canceled,failed"`
WorkerID *uuid.UUID `json:"worker_id,omitempty" format:"uuid"`
FileID uuid.UUID `json:"file_id" format:"uuid"`
Tags map[string]string `json:"tags"`
QueuePosition int `json:"queue_position"`
QueueSize int `json:"queue_size"`
ID uuid.UUID `json:"id" format:"uuid" table:"id"`
CreatedAt time.Time `json:"created_at" format:"date-time" table:"created at,default_sort"`
StartedAt *time.Time `json:"started_at,omitempty" format:"date-time" table:"started at"`
CompletedAt *time.Time `json:"completed_at,omitempty" format:"date-time" table:"completed at"`
CanceledAt *time.Time `json:"canceled_at,omitempty" format:"date-time" table:"canceled at"`
Error string `json:"error,omitempty" table:"error"`
ErrorCode JobErrorCode `json:"error_code,omitempty" enums:"REQUIRED_TEMPLATE_VARIABLES" table:"error code"`
Status ProvisionerJobStatus `json:"status" enums:"pending,running,succeeded,canceling,canceled,failed" table:"status"`
WorkerID *uuid.UUID `json:"worker_id,omitempty" format:"uuid" table:"worker id"`
FileID uuid.UUID `json:"file_id" format:"uuid" table:"file id"`
Tags map[string]string `json:"tags" table:"tags"`
QueuePosition int `json:"queue_position" table:"queue position"`
QueueSize int `json:"queue_size" table:"queue size"`
OrganizationID uuid.UUID `json:"organization_id" format:"uuid" table:"organization id"`
Input ProvisionerJobInput `json:"input" table:"input,recursive_inline"`
Type ProvisionerJobType `json:"type" table:"type"`
AvailableWorkers []uuid.UUID `json:"available_workers,omitempty" format:"uuid" table:"available workers"`
}
// ProvisionerJobLog represents the provisioner log entry annotated with source and level.
+2
View File
@@ -27,6 +27,7 @@ const (
ResourceOrganization RBACResource = "organization"
ResourceOrganizationMember RBACResource = "organization_member"
ResourceProvisionerDaemon RBACResource = "provisioner_daemon"
ResourceProvisionerJobs RBACResource = "provisioner_jobs"
ResourceProvisionerKeys RBACResource = "provisioner_keys"
ResourceReplicas RBACResource = "replicas"
ResourceSystem RBACResource = "system"
@@ -82,6 +83,7 @@ var RBACResourceActions = map[RBACResource][]RBACAction{
ResourceOrganization: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
ResourceOrganizationMember: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
ResourceProvisionerDaemon: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
ResourceProvisionerJobs: {ActionRead},
ResourceProvisionerKeys: {ActionCreate, ActionDelete, ActionRead},
ResourceReplicas: {ActionRead},
ResourceSystem: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},