feat: add queue_position and queue_size to provisioner jobs (#8074)

This commit is contained in:
Kyle Carberry
2023-06-20 15:07:18 -05:00
committed by GitHub
parent bbb0fab1de
commit 69f911dfd5
26 changed files with 417 additions and 75 deletions
+1 -1
View File
@@ -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
View File
@@ -35,7 +35,9 @@
"file_id": "[workspace build file ID]",
"tags": {
"scope": "organization"
}
},
"queue_position": 0,
"queue_size": 0
},
"reason": "initiator",
"resources": [],
+6
View File
@@ -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"
+6
View File
@@ -7169,6 +7169,12 @@
"type": "string",
"format": "uuid"
},
"queue_position": {
"type": "integer"
},
"queue_size": {
"type": "integer"
},
"started_at": {
"type": "string",
"format": "date-time"
+5
View File
@@ -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 {
+32
View File
@@ -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()
+7
View File
@@ -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)
+15
View File
@@ -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 -1
View File
@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.17.2
// sqlc v1.18.0
package database
+2 -1
View File
@@ -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)
+75
View File
@@ -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)
}
}
+84 -1
View File
@@ -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;
+10 -7
View File
@@ -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 {
+3 -1
View File
@@ -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
View File
@@ -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
+11 -8
View File
@@ -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]
+4 -1
View File
@@ -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{},
+13 -11
View File
@@ -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.
+12
View File
@@ -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": {
+12
View File
@@ -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": {
+22
View File
@@ -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": {
+8
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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 = {