mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: add queue_position and queue_size to provisioner jobs (#8074)
This commit is contained in:
@@ -153,7 +153,7 @@ jobs:
|
||||
|
||||
- name: Install sqlc
|
||||
run: |
|
||||
curl -sSL https://github.com/kyleconroy/sqlc/releases/download/v1.17.2/sqlc_1.17.2_linux_amd64.tar.gz | sudo tar -C /usr/bin -xz sqlc
|
||||
curl -sSL https://github.com/kyleconroy/sqlc/releases/download/v1.18.0/sqlc_1.18.0_linux_amd64.tar.gz | sudo tar -C /usr/bin -xz sqlc
|
||||
|
||||
- name: go install tools
|
||||
run: |
|
||||
|
||||
+3
-1
@@ -35,7 +35,9 @@
|
||||
"file_id": "[workspace build file ID]",
|
||||
"tags": {
|
||||
"scope": "organization"
|
||||
}
|
||||
},
|
||||
"queue_position": 0,
|
||||
"queue_size": 0
|
||||
},
|
||||
"reason": "initiator",
|
||||
"resources": [],
|
||||
|
||||
Generated
+6
@@ -7991,6 +7991,12 @@ const docTemplate = `{
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"queue_position": {
|
||||
"type": "integer"
|
||||
},
|
||||
"queue_size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
|
||||
Generated
+6
@@ -7169,6 +7169,12 @@
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"queue_position": {
|
||||
"type": "integer"
|
||||
},
|
||||
"queue_size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
|
||||
@@ -1087,6 +1087,11 @@ func (q *querier) GetProvisionerJobsByIDs(ctx context.Context, ids []uuid.UUID)
|
||||
return q.db.GetProvisionerJobsByIDs(ctx, ids)
|
||||
}
|
||||
|
||||
// TODO: we need to add a provisioner job resource
|
||||
func (q *querier) GetProvisionerJobsByIDsWithQueuePosition(ctx context.Context, ids []uuid.UUID) ([]database.GetProvisionerJobsByIDsWithQueuePositionRow, error) {
|
||||
return q.db.GetProvisionerJobsByIDsWithQueuePosition(ctx, ids)
|
||||
}
|
||||
|
||||
// TODO: We need to create a ProvisionerJob resource type
|
||||
func (q *querier) GetProvisionerJobsCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.ProvisionerJob, error) {
|
||||
// if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceSystem); err != nil {
|
||||
|
||||
@@ -2051,6 +2051,38 @@ func (q *fakeQuerier) GetProvisionerJobsByIDs(_ context.Context, ids []uuid.UUID
|
||||
return jobs, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetProvisionerJobsByIDsWithQueuePosition(_ context.Context, ids []uuid.UUID) ([]database.GetProvisionerJobsByIDsWithQueuePositionRow, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
jobs := make([]database.GetProvisionerJobsByIDsWithQueuePositionRow, 0)
|
||||
queuePosition := int64(1)
|
||||
for _, job := range q.provisionerJobs {
|
||||
for _, id := range ids {
|
||||
if id == job.ID {
|
||||
job := database.GetProvisionerJobsByIDsWithQueuePositionRow{
|
||||
ProvisionerJob: job,
|
||||
}
|
||||
if !job.ProvisionerJob.StartedAt.Valid {
|
||||
job.QueuePosition = queuePosition
|
||||
}
|
||||
jobs = append(jobs, job)
|
||||
break
|
||||
}
|
||||
}
|
||||
if !job.StartedAt.Valid {
|
||||
queuePosition++
|
||||
}
|
||||
}
|
||||
for _, job := range jobs {
|
||||
if !job.ProvisionerJob.StartedAt.Valid {
|
||||
// Set it to the max position!
|
||||
job.QueueSize = queuePosition
|
||||
}
|
||||
}
|
||||
return jobs, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetProvisionerJobsCreatedAfter(_ context.Context, after time.Time) ([]database.ProvisionerJob, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
@@ -507,6 +507,13 @@ func (m metricsStore) GetProvisionerJobsByIDs(ctx context.Context, ids []uuid.UU
|
||||
return jobs, err
|
||||
}
|
||||
|
||||
func (m metricsStore) GetProvisionerJobsByIDsWithQueuePosition(ctx context.Context, ids []uuid.UUID) ([]database.GetProvisionerJobsByIDsWithQueuePositionRow, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.GetProvisionerJobsByIDsWithQueuePosition(ctx, ids)
|
||||
m.queryLatencies.WithLabelValues("GetProvisionerJobsByIDsWithQueuePosition").Observe(time.Since(start).Seconds())
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m metricsStore) GetProvisionerJobsCreatedAfter(ctx context.Context, createdAt time.Time) ([]database.ProvisionerJob, error) {
|
||||
start := time.Now()
|
||||
jobs, err := m.s.GetProvisionerJobsCreatedAfter(ctx, createdAt)
|
||||
|
||||
@@ -928,6 +928,21 @@ func (mr *MockStoreMockRecorder) GetProvisionerJobsByIDs(arg0, arg1 interface{})
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProvisionerJobsByIDs", reflect.TypeOf((*MockStore)(nil).GetProvisionerJobsByIDs), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetProvisionerJobsByIDsWithQueuePosition mocks base method.
|
||||
func (m *MockStore) GetProvisionerJobsByIDsWithQueuePosition(arg0 context.Context, arg1 []uuid.UUID) ([]database.GetProvisionerJobsByIDsWithQueuePositionRow, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetProvisionerJobsByIDsWithQueuePosition", arg0, arg1)
|
||||
ret0, _ := ret[0].([]database.GetProvisionerJobsByIDsWithQueuePositionRow)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetProvisionerJobsByIDsWithQueuePosition indicates an expected call of GetProvisionerJobsByIDsWithQueuePosition.
|
||||
func (mr *MockStoreMockRecorder) GetProvisionerJobsByIDsWithQueuePosition(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProvisionerJobsByIDsWithQueuePosition", reflect.TypeOf((*MockStore)(nil).GetProvisionerJobsByIDsWithQueuePosition), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetProvisionerJobsCreatedAfter mocks base method.
|
||||
func (m *MockStore) GetProvisionerJobsCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.ProvisionerJob, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.17.2
|
||||
// sqlc v1.18.0
|
||||
|
||||
package database
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.17.2
|
||||
// sqlc v1.18.0
|
||||
|
||||
package database
|
||||
|
||||
@@ -90,6 +90,7 @@ type sqlcQuerier interface {
|
||||
GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error)
|
||||
GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (ProvisionerJob, error)
|
||||
GetProvisionerJobsByIDs(ctx context.Context, ids []uuid.UUID) ([]ProvisionerJob, error)
|
||||
GetProvisionerJobsByIDsWithQueuePosition(ctx context.Context, ids []uuid.UUID) ([]GetProvisionerJobsByIDsWithQueuePositionRow, error)
|
||||
GetProvisionerJobsCreatedAfter(ctx context.Context, createdAt time.Time) ([]ProvisionerJob, error)
|
||||
GetProvisionerLogsAfterID(ctx context.Context, arg GetProvisionerLogsAfterIDParams) ([]ProvisionerJobLog, error)
|
||||
GetQuotaAllowanceForUser(ctx context.Context, userID uuid.UUID) (int64, error)
|
||||
|
||||
@@ -5,6 +5,8 @@ package database_test
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -312,3 +314,76 @@ func TestDefaultProxy(t *testing.T) {
|
||||
require.NoError(t, err, "get deployment id")
|
||||
require.Equal(t, depID, found)
|
||||
}
|
||||
|
||||
func TestQueuePosition(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if testing.Short() {
|
||||
t.SkipNow()
|
||||
}
|
||||
sqlDB := testSQLDB(t)
|
||||
err := migrations.Up(sqlDB)
|
||||
require.NoError(t, err)
|
||||
db := database.New(sqlDB)
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
jobCount := 10
|
||||
jobs := []database.ProvisionerJob{}
|
||||
jobIDs := []uuid.UUID{}
|
||||
for i := 0; i < jobCount; i++ {
|
||||
job := dbgen.ProvisionerJob(t, db, database.ProvisionerJob{
|
||||
OrganizationID: org.ID,
|
||||
Tags: database.StringMap{},
|
||||
})
|
||||
jobs = append(jobs, job)
|
||||
jobIDs = append(jobIDs, job.ID)
|
||||
|
||||
// We need a slight amount of time between each insertion to ensure that
|
||||
// the queue position is correct... it's sorted by `created_at`.
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
|
||||
queued, err := db.GetProvisionerJobsByIDsWithQueuePosition(ctx, jobIDs)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, queued, jobCount)
|
||||
sort.Slice(queued, func(i, j int) bool {
|
||||
return queued[i].QueuePosition < queued[j].QueuePosition
|
||||
})
|
||||
// Ensure that the queue positions are correct based on insertion ID!
|
||||
for index, job := range queued {
|
||||
require.Equal(t, job.QueuePosition, int64(index+1))
|
||||
require.Equal(t, job.ProvisionerJob.ID, jobs[index].ID)
|
||||
}
|
||||
|
||||
job, err := db.AcquireProvisionerJob(ctx, database.AcquireProvisionerJobParams{
|
||||
StartedAt: sql.NullTime{
|
||||
Time: database.Now(),
|
||||
Valid: true,
|
||||
},
|
||||
Types: database.AllProvisionerTypeValues(),
|
||||
WorkerID: uuid.NullUUID{
|
||||
UUID: uuid.New(),
|
||||
Valid: true,
|
||||
},
|
||||
Tags: json.RawMessage("{}"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, jobs[0].ID, job.ID)
|
||||
|
||||
queued, err = db.GetProvisionerJobsByIDsWithQueuePosition(ctx, jobIDs)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, queued, jobCount)
|
||||
sort.Slice(queued, func(i, j int) bool {
|
||||
return queued[i].QueuePosition < queued[j].QueuePosition
|
||||
})
|
||||
// Ensure that queue positions are updated now that the first job has been acquired!
|
||||
for index, job := range queued {
|
||||
if index == 0 {
|
||||
require.Equal(t, job.QueuePosition, int64(0))
|
||||
continue
|
||||
}
|
||||
require.Equal(t, job.QueuePosition, int64(index))
|
||||
require.Equal(t, job.ProvisionerJob.ID, jobs[index].ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.17.2
|
||||
// sqlc v1.18.0
|
||||
|
||||
package database
|
||||
|
||||
@@ -2287,6 +2287,89 @@ func (q *sqlQuerier) GetProvisionerJobsByIDs(ctx context.Context, ids []uuid.UUI
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getProvisionerJobsByIDsWithQueuePosition = `-- name: GetProvisionerJobsByIDsWithQueuePosition :many
|
||||
WITH unstarted_jobs AS (
|
||||
SELECT
|
||||
id, created_at
|
||||
FROM
|
||||
provisioner_jobs
|
||||
WHERE
|
||||
started_at IS NULL
|
||||
),
|
||||
queue_position AS (
|
||||
SELECT
|
||||
id,
|
||||
ROW_NUMBER() OVER (ORDER BY created_at ASC) AS queue_position
|
||||
FROM
|
||||
unstarted_jobs
|
||||
),
|
||||
queue_size AS (
|
||||
SELECT COUNT(*) as count FROM unstarted_jobs
|
||||
)
|
||||
SELECT
|
||||
pj.id, pj.created_at, pj.updated_at, pj.started_at, pj.canceled_at, pj.completed_at, pj.error, pj.organization_id, pj.initiator_id, pj.provisioner, pj.storage_method, pj.type, pj.input, pj.worker_id, pj.file_id, pj.tags, pj.error_code, pj.trace_metadata,
|
||||
COALESCE(qp.queue_position, 0) AS queue_position,
|
||||
COALESCE(qs.count, 0) AS queue_size
|
||||
FROM
|
||||
provisioner_jobs pj
|
||||
LEFT JOIN
|
||||
queue_position qp ON qp.id = pj.id
|
||||
LEFT JOIN
|
||||
queue_size qs ON TRUE
|
||||
WHERE
|
||||
pj.id = ANY($1 :: uuid [ ])
|
||||
`
|
||||
|
||||
type GetProvisionerJobsByIDsWithQueuePositionRow struct {
|
||||
ProvisionerJob ProvisionerJob `db:"provisionerjob" json:"provisionerjob"`
|
||||
QueuePosition int64 `db:"queue_position" json:"queue_position"`
|
||||
QueueSize int64 `db:"queue_size" json:"queue_size"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetProvisionerJobsByIDsWithQueuePosition(ctx context.Context, ids []uuid.UUID) ([]GetProvisionerJobsByIDsWithQueuePositionRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getProvisionerJobsByIDsWithQueuePosition, pq.Array(ids))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetProvisionerJobsByIDsWithQueuePositionRow
|
||||
for rows.Next() {
|
||||
var i GetProvisionerJobsByIDsWithQueuePositionRow
|
||||
if err := rows.Scan(
|
||||
&i.ProvisionerJob.ID,
|
||||
&i.ProvisionerJob.CreatedAt,
|
||||
&i.ProvisionerJob.UpdatedAt,
|
||||
&i.ProvisionerJob.StartedAt,
|
||||
&i.ProvisionerJob.CanceledAt,
|
||||
&i.ProvisionerJob.CompletedAt,
|
||||
&i.ProvisionerJob.Error,
|
||||
&i.ProvisionerJob.OrganizationID,
|
||||
&i.ProvisionerJob.InitiatorID,
|
||||
&i.ProvisionerJob.Provisioner,
|
||||
&i.ProvisionerJob.StorageMethod,
|
||||
&i.ProvisionerJob.Type,
|
||||
&i.ProvisionerJob.Input,
|
||||
&i.ProvisionerJob.WorkerID,
|
||||
&i.ProvisionerJob.FileID,
|
||||
&i.ProvisionerJob.Tags,
|
||||
&i.ProvisionerJob.ErrorCode,
|
||||
&i.ProvisionerJob.TraceMetadata,
|
||||
&i.QueuePosition,
|
||||
&i.QueueSize,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getProvisionerJobsCreatedAfter = `-- name: GetProvisionerJobsCreatedAfter :many
|
||||
SELECT id, created_at, updated_at, started_at, canceled_at, completed_at, error, organization_id, initiator_id, provisioner, storage_method, type, input, worker_id, file_id, tags, error_code, trace_metadata FROM provisioner_jobs WHERE created_at > $1
|
||||
`
|
||||
|
||||
@@ -47,6 +47,38 @@ FROM
|
||||
WHERE
|
||||
id = ANY(@ids :: uuid [ ]);
|
||||
|
||||
-- name: GetProvisionerJobsByIDsWithQueuePosition :many
|
||||
WITH unstarted_jobs AS (
|
||||
SELECT
|
||||
id, created_at
|
||||
FROM
|
||||
provisioner_jobs
|
||||
WHERE
|
||||
started_at IS NULL
|
||||
),
|
||||
queue_position AS (
|
||||
SELECT
|
||||
id,
|
||||
ROW_NUMBER() OVER (ORDER BY created_at ASC) AS queue_position
|
||||
FROM
|
||||
unstarted_jobs
|
||||
),
|
||||
queue_size AS (
|
||||
SELECT COUNT(*) as count FROM unstarted_jobs
|
||||
)
|
||||
SELECT
|
||||
sqlc.embed(pj),
|
||||
COALESCE(qp.queue_position, 0) AS queue_position,
|
||||
COALESCE(qs.count, 0) AS queue_size
|
||||
FROM
|
||||
provisioner_jobs pj
|
||||
LEFT JOIN
|
||||
queue_position qp ON qp.id = pj.id
|
||||
LEFT JOIN
|
||||
queue_size qs ON TRUE
|
||||
WHERE
|
||||
pj.id = ANY(@ids :: uuid [ ]);
|
||||
|
||||
-- name: GetProvisionerJobsCreatedAfter :many
|
||||
SELECT * FROM provisioner_jobs WHERE created_at > $1;
|
||||
|
||||
|
||||
@@ -195,14 +195,17 @@ func convertProvisionerJobLog(provisionerJobLog database.ProvisionerJobLog) code
|
||||
}
|
||||
}
|
||||
|
||||
func convertProvisionerJob(provisionerJob database.ProvisionerJob) codersdk.ProvisionerJob {
|
||||
func convertProvisionerJob(pj database.GetProvisionerJobsByIDsWithQueuePositionRow) codersdk.ProvisionerJob {
|
||||
provisionerJob := pj.ProvisionerJob
|
||||
job := codersdk.ProvisionerJob{
|
||||
ID: provisionerJob.ID,
|
||||
CreatedAt: provisionerJob.CreatedAt,
|
||||
Error: provisionerJob.Error.String,
|
||||
ErrorCode: codersdk.JobErrorCode(provisionerJob.ErrorCode.String),
|
||||
FileID: provisionerJob.FileID,
|
||||
Tags: provisionerJob.Tags,
|
||||
ID: provisionerJob.ID,
|
||||
CreatedAt: provisionerJob.CreatedAt,
|
||||
Error: provisionerJob.Error.String,
|
||||
ErrorCode: codersdk.JobErrorCode(provisionerJob.ErrorCode.String),
|
||||
FileID: provisionerJob.FileID,
|
||||
Tags: provisionerJob.Tags,
|
||||
QueuePosition: int(pj.QueuePosition),
|
||||
QueueSize: int(pj.QueueSize),
|
||||
}
|
||||
// Applying values optional to the struct.
|
||||
if provisionerJob.StartedAt.Valid {
|
||||
|
||||
@@ -126,7 +126,9 @@ func TestConvertProvisionerJob_Unit(t *testing.T) {
|
||||
testCase := testCase
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
actual := convertProvisionerJob(testCase.input)
|
||||
actual := convertProvisionerJob(database.GetProvisionerJobsByIDsWithQueuePositionRow{
|
||||
ProvisionerJob: testCase.input,
|
||||
})
|
||||
assert.Equal(t, testCase.expected, actual)
|
||||
})
|
||||
}
|
||||
|
||||
+48
-41
@@ -44,8 +44,8 @@ func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
templateVersion := httpmw.TemplateVersionParam(r)
|
||||
|
||||
job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
|
||||
if err != nil {
|
||||
jobs, err := api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, []uuid.UUID{templateVersion.JobID})
|
||||
if err != nil || len(jobs) == 0 {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
Detail: err.Error(),
|
||||
@@ -62,7 +62,7 @@ func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
schemas, err := api.Database.GetParameterSchemasByJobID(ctx, job.ID)
|
||||
schemas, err := api.Database.GetParameterSchemasByJobID(ctx, jobs[0].ProvisionerJob.ID)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
err = nil
|
||||
}
|
||||
@@ -79,7 +79,7 @@ func (api *API) templateVersion(rw http.ResponseWriter, r *http.Request) {
|
||||
warnings = append(warnings, codersdk.TemplateVersionWarningUnsupportedWorkspaces)
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job), user, warnings))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), user, warnings))
|
||||
}
|
||||
|
||||
// @Summary Patch template version by ID
|
||||
@@ -155,8 +155,8 @@ func (api *API) patchTemplateVersion(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
|
||||
if err != nil {
|
||||
jobs, err := api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, []uuid.UUID{templateVersion.JobID})
|
||||
if err != nil || len(jobs) == 0 {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
Detail: err.Error(),
|
||||
@@ -173,7 +173,7 @@ func (api *API) patchTemplateVersion(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(updatedTemplateVersion, convertProvisionerJob(job), user, nil))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(updatedTemplateVersion, convertProvisionerJob(jobs[0]), user, nil))
|
||||
}
|
||||
|
||||
// @Summary Cancel template version by ID
|
||||
@@ -517,7 +517,10 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, convertProvisionerJob(provisionerJob))
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, convertProvisionerJob(database.GetProvisionerJobsByIDsWithQueuePositionRow{
|
||||
ProvisionerJob: provisionerJob,
|
||||
QueuePosition: 0,
|
||||
}))
|
||||
}
|
||||
|
||||
// @Summary Get template version dry-run by job ID
|
||||
@@ -554,7 +557,7 @@ func (api *API) templateVersionDryRunResources(rw http.ResponseWriter, r *http.R
|
||||
return
|
||||
}
|
||||
|
||||
api.provisionerJobResources(rw, r, job)
|
||||
api.provisionerJobResources(rw, r, job.ProvisionerJob)
|
||||
}
|
||||
|
||||
// @Summary Get template version dry-run logs by job ID
|
||||
@@ -575,7 +578,7 @@ func (api *API) templateVersionDryRunLogs(rw http.ResponseWriter, r *http.Reques
|
||||
return
|
||||
}
|
||||
|
||||
api.provisionerJobLogs(rw, r, job)
|
||||
api.provisionerJobLogs(rw, r, job.ProvisionerJob)
|
||||
}
|
||||
|
||||
// @Summary Cancel template version dry-run by job ID
|
||||
@@ -596,18 +599,18 @@ func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
if !api.Authorize(r, rbac.ActionUpdate,
|
||||
rbac.ResourceWorkspace.InOrg(templateVersion.OrganizationID).WithOwner(job.InitiatorID.String())) {
|
||||
rbac.ResourceWorkspace.InOrg(templateVersion.OrganizationID).WithOwner(job.ProvisionerJob.InitiatorID.String())) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
|
||||
if job.CompletedAt.Valid {
|
||||
if job.ProvisionerJob.CompletedAt.Valid {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Job has already completed.",
|
||||
})
|
||||
return
|
||||
}
|
||||
if job.CanceledAt.Valid {
|
||||
if job.ProvisionerJob.CanceledAt.Valid {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Job has already been marked as canceled.",
|
||||
})
|
||||
@@ -615,7 +618,7 @@ func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http
|
||||
}
|
||||
|
||||
err := api.Database.UpdateProvisionerJobWithCancelByID(ctx, database.UpdateProvisionerJobWithCancelByIDParams{
|
||||
ID: job.ID,
|
||||
ID: job.ProvisionerJob.ID,
|
||||
CanceledAt: sql.NullTime{
|
||||
Time: database.Now(),
|
||||
Valid: true,
|
||||
@@ -623,7 +626,7 @@ func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http
|
||||
CompletedAt: sql.NullTime{
|
||||
Time: database.Now(),
|
||||
// If the job is running, don't mark it completed!
|
||||
Valid: !job.WorkerID.Valid,
|
||||
Valid: !job.ProvisionerJob.WorkerID.Valid,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -639,7 +642,7 @@ func (api *API) patchTemplateVersionDryRunCancel(rw http.ResponseWriter, r *http
|
||||
})
|
||||
}
|
||||
|
||||
func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Request) (database.ProvisionerJob, bool) {
|
||||
func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Request) (database.GetProvisionerJobsByIDsWithQueuePositionRow, bool) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
templateVersion = httpmw.TemplateVersionParam(r)
|
||||
@@ -652,48 +655,49 @@ func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Re
|
||||
Message: fmt.Sprintf("Job ID %q must be a valid UUID.", jobID),
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return database.ProvisionerJob{}, false
|
||||
return database.GetProvisionerJobsByIDsWithQueuePositionRow{}, false
|
||||
}
|
||||
|
||||
job, err := api.Database.GetProvisionerJobByID(ctx, jobUUID)
|
||||
jobs, err := api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, []uuid.UUID{jobUUID})
|
||||
if httpapi.Is404Error(err) {
|
||||
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
|
||||
Message: fmt.Sprintf("Provisioner job %q not found.", jobUUID),
|
||||
})
|
||||
return database.ProvisionerJob{}, false
|
||||
return database.GetProvisionerJobsByIDsWithQueuePositionRow{}, false
|
||||
}
|
||||
if err != nil {
|
||||
if err != nil || len(jobs) == 0 {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return database.ProvisionerJob{}, false
|
||||
return database.GetProvisionerJobsByIDsWithQueuePositionRow{}, false
|
||||
}
|
||||
if job.Type != database.ProvisionerJobTypeTemplateVersionDryRun {
|
||||
job := jobs[0]
|
||||
if job.ProvisionerJob.Type != database.ProvisionerJobTypeTemplateVersionDryRun {
|
||||
httpapi.Forbidden(rw)
|
||||
return database.ProvisionerJob{}, false
|
||||
return database.GetProvisionerJobsByIDsWithQueuePositionRow{}, false
|
||||
}
|
||||
|
||||
// Do a workspace resource check since it's basically a workspace dry-run.
|
||||
if !api.Authorize(r, rbac.ActionRead,
|
||||
rbac.ResourceWorkspace.InOrg(templateVersion.OrganizationID).WithOwner(job.InitiatorID.String())) {
|
||||
rbac.ResourceWorkspace.InOrg(templateVersion.OrganizationID).WithOwner(job.ProvisionerJob.InitiatorID.String())) {
|
||||
httpapi.Forbidden(rw)
|
||||
return database.ProvisionerJob{}, false
|
||||
return database.GetProvisionerJobsByIDsWithQueuePositionRow{}, false
|
||||
}
|
||||
|
||||
// Verify that the template version is the one used in the request.
|
||||
var input provisionerdserver.TemplateVersionDryRunJob
|
||||
err = json.Unmarshal(job.Input, &input)
|
||||
err = json.Unmarshal(job.ProvisionerJob.Input, &input)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error unmarshalling job metadata.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return database.ProvisionerJob{}, false
|
||||
return database.GetProvisionerJobsByIDsWithQueuePositionRow{}, false
|
||||
}
|
||||
if input.TemplateVersionID != templateVersion.ID {
|
||||
httpapi.Forbidden(rw)
|
||||
return database.ProvisionerJob{}, false
|
||||
return database.GetProvisionerJobsByIDsWithQueuePositionRow{}, false
|
||||
}
|
||||
|
||||
return job, true
|
||||
@@ -762,7 +766,7 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
|
||||
for _, version := range versions {
|
||||
jobIDs = append(jobIDs, version.JobID)
|
||||
}
|
||||
jobs, err := store.GetProvisionerJobsByIDs(ctx, jobIDs)
|
||||
jobs, err := store.GetProvisionerJobsByIDsWithQueuePosition(ctx, jobIDs)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
@@ -770,9 +774,9 @@ func (api *API) templateVersionsByTemplate(rw http.ResponseWriter, r *http.Reque
|
||||
})
|
||||
return err
|
||||
}
|
||||
jobByID := map[string]database.ProvisionerJob{}
|
||||
jobByID := map[string]database.GetProvisionerJobsByIDsWithQueuePositionRow{}
|
||||
for _, job := range jobs {
|
||||
jobByID[job.ID.String()] = job
|
||||
jobByID[job.ProvisionerJob.ID.String()] = job
|
||||
}
|
||||
|
||||
for _, version := range versions {
|
||||
@@ -837,8 +841,8 @@ func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
return
|
||||
}
|
||||
job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
|
||||
if err != nil {
|
||||
jobs, err := api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, []uuid.UUID{templateVersion.JobID})
|
||||
if err != nil || len(jobs) == 0 {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
Detail: err.Error(),
|
||||
@@ -855,7 +859,7 @@ func (api *API) templateVersionByName(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job), user, nil))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), user, nil))
|
||||
}
|
||||
|
||||
// @Summary Get template version by organization, template, and name
|
||||
@@ -911,8 +915,8 @@ func (api *API) templateVersionByOrganizationTemplateAndName(rw http.ResponseWri
|
||||
})
|
||||
return
|
||||
}
|
||||
job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
|
||||
if err != nil {
|
||||
jobs, err := api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, []uuid.UUID{templateVersion.JobID})
|
||||
if err != nil || len(jobs) == 0 {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
Detail: err.Error(),
|
||||
@@ -929,7 +933,7 @@ func (api *API) templateVersionByOrganizationTemplateAndName(rw http.ResponseWri
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(job), user, nil))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(templateVersion, convertProvisionerJob(jobs[0]), user, nil))
|
||||
}
|
||||
|
||||
// @Summary Get previous template version by organization, template, and name
|
||||
@@ -1006,8 +1010,8 @@ func (api *API) previousTemplateVersionByOrganizationTemplateAndName(rw http.Res
|
||||
return
|
||||
}
|
||||
|
||||
job, err := api.Database.GetProvisionerJobByID(ctx, previousTemplateVersion.JobID)
|
||||
if err != nil {
|
||||
jobs, err := api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, []uuid.UUID{previousTemplateVersion.JobID})
|
||||
if err != nil || len(jobs) == 0 {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
Detail: err.Error(),
|
||||
@@ -1024,7 +1028,7 @@ func (api *API) previousTemplateVersionByOrganizationTemplateAndName(rw http.Res
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(previousTemplateVersion, convertProvisionerJob(job), user, nil))
|
||||
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersion(previousTemplateVersion, convertProvisionerJob(jobs[0]), user, nil))
|
||||
}
|
||||
|
||||
// @Summary Update active template version by template ID
|
||||
@@ -1336,7 +1340,10 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, convertTemplateVersion(templateVersion, convertProvisionerJob(provisionerJob), user, nil))
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, convertTemplateVersion(templateVersion, convertProvisionerJob(database.GetProvisionerJobsByIDsWithQueuePositionRow{
|
||||
ProvisionerJob: provisionerJob,
|
||||
QueuePosition: 0,
|
||||
}), user, nil))
|
||||
}
|
||||
|
||||
// templateVersionResources returns the workspace agent resources associated
|
||||
|
||||
@@ -377,7 +377,10 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
||||
apiBuild, err := api.convertWorkspaceBuild(
|
||||
*workspaceBuild,
|
||||
workspace,
|
||||
*provisionerJob,
|
||||
database.GetProvisionerJobsByIDsWithQueuePositionRow{
|
||||
ProvisionerJob: *provisionerJob,
|
||||
QueuePosition: 0,
|
||||
},
|
||||
users,
|
||||
[]database.WorkspaceResource{},
|
||||
[]database.WorkspaceResourceMetadatum{},
|
||||
@@ -610,7 +613,7 @@ func (api *API) workspaceBuildState(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
type workspaceBuildsData struct {
|
||||
users []database.User
|
||||
jobs []database.ProvisionerJob
|
||||
jobs []database.GetProvisionerJobsByIDsWithQueuePositionRow
|
||||
templateVersions []database.TemplateVersion
|
||||
resources []database.WorkspaceResource
|
||||
metadata []database.WorkspaceResourceMetadatum
|
||||
@@ -635,7 +638,7 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaces []database.W
|
||||
for _, build := range workspaceBuilds {
|
||||
jobIDs = append(jobIDs, build.JobID)
|
||||
}
|
||||
jobs, err := api.Database.GetProvisionerJobsByIDs(ctx, jobIDs)
|
||||
jobs, err := api.Database.GetProvisionerJobsByIDsWithQueuePosition(ctx, jobIDs)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return workspaceBuildsData{}, xerrors.Errorf("get provisioner jobs: %w", err)
|
||||
}
|
||||
@@ -717,7 +720,7 @@ func (api *API) workspaceBuildsData(ctx context.Context, workspaces []database.W
|
||||
func (api *API) convertWorkspaceBuilds(
|
||||
workspaceBuilds []database.WorkspaceBuild,
|
||||
workspaces []database.Workspace,
|
||||
jobs []database.ProvisionerJob,
|
||||
jobs []database.GetProvisionerJobsByIDsWithQueuePositionRow,
|
||||
users []database.User,
|
||||
workspaceResources []database.WorkspaceResource,
|
||||
resourceMetadata []database.WorkspaceResourceMetadatum,
|
||||
@@ -729,9 +732,9 @@ func (api *API) convertWorkspaceBuilds(
|
||||
for _, workspace := range workspaces {
|
||||
workspaceByID[workspace.ID] = workspace
|
||||
}
|
||||
jobByID := map[uuid.UUID]database.ProvisionerJob{}
|
||||
jobByID := map[uuid.UUID]database.GetProvisionerJobsByIDsWithQueuePositionRow{}
|
||||
for _, job := range jobs {
|
||||
jobByID[job.ID] = job
|
||||
jobByID[job.ProvisionerJob.ID] = job
|
||||
}
|
||||
templateVersionByID := map[uuid.UUID]database.TemplateVersion{}
|
||||
for _, templateVersion := range templateVersions {
|
||||
@@ -778,7 +781,7 @@ func (api *API) convertWorkspaceBuilds(
|
||||
func (api *API) convertWorkspaceBuild(
|
||||
build database.WorkspaceBuild,
|
||||
workspace database.Workspace,
|
||||
job database.ProvisionerJob,
|
||||
job database.GetProvisionerJobsByIDsWithQueuePositionRow,
|
||||
users []database.User,
|
||||
workspaceResources []database.WorkspaceResource,
|
||||
resourceMetadata []database.WorkspaceResourceMetadatum,
|
||||
@@ -816,7 +819,7 @@ func (api *API) convertWorkspaceBuild(
|
||||
return codersdk.WorkspaceBuild{}, xerrors.Errorf("build initiator not found for workspace: %q", workspace.Name)
|
||||
}
|
||||
|
||||
resources := resourcesByJobID[job.ID]
|
||||
resources := resourcesByJobID[job.ProvisionerJob.ID]
|
||||
apiResources := make([]codersdk.WorkspaceResource, 0)
|
||||
for _, resource := range resources {
|
||||
agents := agentsByResourceID[resource.ID]
|
||||
|
||||
@@ -487,7 +487,10 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
|
||||
apiBuild, err := api.convertWorkspaceBuild(
|
||||
*workspaceBuild,
|
||||
workspace,
|
||||
*provisionerJob,
|
||||
database.GetProvisionerJobsByIDsWithQueuePositionRow{
|
||||
ProvisionerJob: *provisionerJob,
|
||||
QueuePosition: 0,
|
||||
},
|
||||
users,
|
||||
[]database.WorkspaceResource{},
|
||||
[]database.WorkspaceResourceMetadatum{},
|
||||
|
||||
@@ -75,17 +75,19 @@ const (
|
||||
|
||||
// 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:"MISSING_TEMPLATE_PARAMETER,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"`
|
||||
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:"MISSING_TEMPLATE_PARAMETER,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"`
|
||||
}
|
||||
|
||||
// ProvisionerJobLog represents the provisioner log entry annotated with source and level.
|
||||
|
||||
@@ -42,6 +42,8 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -198,6 +200,8 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild} \
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -744,6 +748,8 @@ curl -X GET http://coder-server:8080/api/v2/workspacebuilds/{workspacebuild}/sta
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -905,6 +911,8 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/builds \
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -1042,6 +1050,8 @@ Status Code **200**
|
||||
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
|
||||
| `»» file_id` | string(uuid) | false | | |
|
||||
| `»» id` | string(uuid) | false | | |
|
||||
| `»» queue_position` | integer | false | | |
|
||||
| `»» queue_size` | integer | false | | |
|
||||
| `»» started_at` | string(date-time) | false | | |
|
||||
| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | |
|
||||
| `»» tags` | object | false | | |
|
||||
@@ -1242,6 +1252,8 @@ curl -X POST http://coder-server:8080/api/v2/workspaces/{workspace}/builds \
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
|
||||
@@ -3174,6 +3174,8 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -3195,6 +3197,8 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
| `error_code` | [codersdk.JobErrorCode](#codersdkjoberrorcode) | false | | |
|
||||
| `file_id` | string | false | | |
|
||||
| `id` | string | false | | |
|
||||
| `queue_position` | integer | false | | |
|
||||
| `queue_size` | integer | false | | |
|
||||
| `started_at` | string | false | | |
|
||||
| `status` | [codersdk.ProvisionerJobStatus](#codersdkprovisionerjobstatus) | false | | |
|
||||
| `tags` | object | false | | |
|
||||
@@ -3915,6 +3919,8 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -4450,6 +4456,8 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -4998,6 +5006,8 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -5489,6 +5499,8 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
|
||||
@@ -379,6 +379,8 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -457,6 +459,8 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -558,6 +562,8 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -859,6 +865,8 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -912,6 +920,8 @@ Status Code **200**
|
||||
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
|
||||
| `»» file_id` | string(uuid) | false | | |
|
||||
| `»» id` | string(uuid) | false | | |
|
||||
| `»» queue_position` | integer | false | | |
|
||||
| `»» queue_size` | integer | false | | |
|
||||
| `»» started_at` | string(date-time) | false | | |
|
||||
| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | |
|
||||
| `»» tags` | object | false | | |
|
||||
@@ -1048,6 +1058,8 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions/{templ
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -1101,6 +1113,8 @@ Status Code **200**
|
||||
| `»» error_code` | [codersdk.JobErrorCode](schemas.md#codersdkjoberrorcode) | false | | |
|
||||
| `»» file_id` | string(uuid) | false | | |
|
||||
| `»» id` | string(uuid) | false | | |
|
||||
| `»» queue_position` | integer | false | | |
|
||||
| `»» queue_size` | integer | false | | |
|
||||
| `»» started_at` | string(date-time) | false | | |
|
||||
| `»» status` | [codersdk.ProvisionerJobStatus](schemas.md#codersdkprovisionerjobstatus) | false | | |
|
||||
| `»» tags` | object | false | | |
|
||||
@@ -1181,6 +1195,8 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion} \
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -1267,6 +1283,8 @@ curl -X PATCH http://coder-server:8080/api/v2/templateversions/{templateversion}
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -1390,6 +1408,8 @@ curl -X POST http://coder-server:8080/api/v2/templateversions/{templateversion}/
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -1441,6 +1461,8 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
|
||||
@@ -66,6 +66,8 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/member
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -243,6 +245,8 @@ curl -X GET http://coder-server:8080/api/v2/users/{user}/workspace/{workspacenam
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -444,6 +448,8 @@ curl -X GET http://coder-server:8080/api/v2/workspaces \
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
@@ -618,6 +624,8 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace} \
|
||||
"error_code": "MISSING_TEMPLATE_PARAMETER",
|
||||
"file_id": "8a0cfb4f-ddc9-436d-91bb-75133c583767",
|
||||
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
|
||||
"queue_position": 0,
|
||||
"queue_size": 0,
|
||||
"started_at": "2019-08-24T14:15:22Z",
|
||||
"status": "pending",
|
||||
"tags": {
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ RUN mkdir --parents "$GOPATH" && \
|
||||
# charts and values files
|
||||
go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.5.0 && \
|
||||
# sqlc for Go code generation
|
||||
go install github.com/kyleconroy/sqlc/cmd/sqlc@v1.17.2 && \
|
||||
go install github.com/kyleconroy/sqlc/cmd/sqlc@v1.18.0 && \
|
||||
# gcr-cleaner-cli used by CI to prune unused images
|
||||
go install github.com/sethvargo/gcr-cleaner/cmd/gcr-cleaner-cli@v0.5.1 && \
|
||||
# ruleguard for checking custom rules, without needing to run all of
|
||||
|
||||
@@ -641,6 +641,8 @@ export interface ProvisionerJob {
|
||||
readonly worker_id?: string
|
||||
readonly file_id: string
|
||||
readonly tags: Record<string, string>
|
||||
readonly queue_position: number
|
||||
readonly queue_size: number
|
||||
}
|
||||
|
||||
// From codersdk/provisionerdaemons.go
|
||||
|
||||
@@ -286,6 +286,8 @@ export const MockProvisionerJob: TypesGen.ProvisionerJob = {
|
||||
file_id: MockOrganization.id,
|
||||
completed_at: "2022-05-17T17:39:01.382927298Z",
|
||||
tags: {},
|
||||
queue_position: 0,
|
||||
queue_size: 0,
|
||||
}
|
||||
|
||||
export const MockFailedProvisionerJob: TypesGen.ProvisionerJob = {
|
||||
|
||||
Reference in New Issue
Block a user