mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
feat: add provisioner job metadata (#16454)
This change adds metadata to provisioner jobs to help with rendering related tempaltes and workspaces in the UI. Updates #15084
This commit is contained in:
committed by
GitHub
parent
44d9f5ff4e
commit
b04d883348
28
coderd/apidoc/docs.go
generated
28
coderd/apidoc/docs.go
generated
@ -13125,6 +13125,9 @@ const docTemplate = `{
|
||||
"input": {
|
||||
"$ref": "#/definitions/codersdk.ProvisionerJobInput"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/definitions/codersdk.ProvisionerJobMetadata"
|
||||
},
|
||||
"organization_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
@ -13220,6 +13223,31 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ProvisionerJobMetadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"template_display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"template_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_version_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"workspace_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ProvisionerJobStatus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
28
coderd/apidoc/swagger.json
generated
28
coderd/apidoc/swagger.json
generated
@ -11852,6 +11852,9 @@
|
||||
"input": {
|
||||
"$ref": "#/definitions/codersdk.ProvisionerJobInput"
|
||||
},
|
||||
"metadata": {
|
||||
"$ref": "#/definitions/codersdk.ProvisionerJobMetadata"
|
||||
},
|
||||
"organization_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
@ -11941,6 +11944,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ProvisionerJobMetadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"template_display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"template_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"template_version_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"workspace_name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.ProvisionerJobStatus": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
@ -4117,6 +4117,45 @@ func (q *FakeQuerier) GetProvisionerJobsByOrganizationAndStatusWithQueuePosition
|
||||
QueuePosition: rowQP.QueuePosition,
|
||||
QueueSize: rowQP.QueueSize,
|
||||
}
|
||||
|
||||
// Start add metadata.
|
||||
var input codersdk.ProvisionerJobInput
|
||||
err := json.Unmarshal([]byte(job.Input), &input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
templateVersionID := input.TemplateVersionID
|
||||
if input.WorkspaceBuildID != nil {
|
||||
workspaceBuild, err := q.getWorkspaceBuildByIDNoLock(ctx, *input.WorkspaceBuildID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
workspace, err := q.getWorkspaceByIDNoLock(ctx, workspaceBuild.WorkspaceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
row.WorkspaceID = uuid.NullUUID{UUID: workspace.ID, Valid: true}
|
||||
row.WorkspaceName = workspace.Name
|
||||
if templateVersionID == nil {
|
||||
templateVersionID = &workspaceBuild.TemplateVersionID
|
||||
}
|
||||
}
|
||||
if templateVersionID != nil {
|
||||
templateVersion, err := q.getTemplateVersionByIDNoLock(ctx, *templateVersionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
row.TemplateVersionName = templateVersion.Name
|
||||
template, err := q.getTemplateByIDNoLock(ctx, templateVersion.TemplateID.UUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
row.TemplateID = uuid.NullUUID{UUID: template.ID, Valid: true}
|
||||
row.TemplateName = template.Name
|
||||
row.TemplateDisplayName = template.DisplayName
|
||||
}
|
||||
// End add metadata.
|
||||
|
||||
if row.QueuePosition > 0 {
|
||||
var availableWorkers []database.ProvisionerDaemon
|
||||
for _, daemon := range q.provisionerDaemons {
|
||||
|
@ -6265,13 +6265,29 @@ SELECT
|
||||
AND pj.organization_id = pd.organization_id
|
||||
AND pj.provisioner = ANY(pd.provisioners)
|
||||
AND provisioner_tagset_contains(pd.tags, pj.tags)
|
||||
) AS available_workers
|
||||
) AS available_workers,
|
||||
-- Include template and workspace information.
|
||||
COALESCE(tv.name, '') AS template_version_name,
|
||||
t.id AS template_id,
|
||||
COALESCE(t.name, '') AS template_name,
|
||||
COALESCE(t.display_name, '') AS template_display_name,
|
||||
w.id AS workspace_id,
|
||||
COALESCE(w.name, '') AS workspace_name
|
||||
FROM
|
||||
provisioner_jobs pj
|
||||
LEFT JOIN
|
||||
queue_position qp ON qp.id = pj.id
|
||||
LEFT JOIN
|
||||
queue_size qs ON TRUE
|
||||
LEFT JOIN
|
||||
workspace_builds wb ON wb.id = CASE WHEN pj.input ? 'workspace_build_id' THEN (pj.input->>'workspace_build_id')::uuid END
|
||||
LEFT JOIN
|
||||
workspaces w ON wb.workspace_id = w.id
|
||||
LEFT JOIN
|
||||
-- We should always have a template version, either explicitly or implicitly via workspace build.
|
||||
template_versions tv ON tv.id = CASE WHEN pj.input ? 'template_version_id' THEN (pj.input->>'template_version_id')::uuid ELSE wb.template_version_id END
|
||||
LEFT JOIN
|
||||
templates t ON tv.template_id = t.id
|
||||
WHERE
|
||||
($1::uuid IS NULL OR pj.organization_id = $1)
|
||||
AND (COALESCE(array_length($2::uuid[], 1), 0) = 0 OR pj.id = ANY($2::uuid[]))
|
||||
@ -6279,7 +6295,13 @@ WHERE
|
||||
GROUP BY
|
||||
pj.id,
|
||||
qp.queue_position,
|
||||
qs.count
|
||||
qs.count,
|
||||
tv.name,
|
||||
t.id,
|
||||
t.name,
|
||||
t.display_name,
|
||||
w.id,
|
||||
w.name
|
||||
ORDER BY
|
||||
pj.created_at DESC
|
||||
LIMIT
|
||||
@ -6294,10 +6316,16 @@ type GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerPar
|
||||
}
|
||||
|
||||
type GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerRow struct {
|
||||
ProvisionerJob ProvisionerJob `db:"provisioner_job" json:"provisioner_job"`
|
||||
QueuePosition int64 `db:"queue_position" json:"queue_position"`
|
||||
QueueSize int64 `db:"queue_size" json:"queue_size"`
|
||||
AvailableWorkers []uuid.UUID `db:"available_workers" json:"available_workers"`
|
||||
ProvisionerJob ProvisionerJob `db:"provisioner_job" json:"provisioner_job"`
|
||||
QueuePosition int64 `db:"queue_position" json:"queue_position"`
|
||||
QueueSize int64 `db:"queue_size" json:"queue_size"`
|
||||
AvailableWorkers []uuid.UUID `db:"available_workers" json:"available_workers"`
|
||||
TemplateVersionName string `db:"template_version_name" json:"template_version_name"`
|
||||
TemplateID uuid.NullUUID `db:"template_id" json:"template_id"`
|
||||
TemplateName string `db:"template_name" json:"template_name"`
|
||||
TemplateDisplayName string `db:"template_display_name" json:"template_display_name"`
|
||||
WorkspaceID uuid.NullUUID `db:"workspace_id" json:"workspace_id"`
|
||||
WorkspaceName string `db:"workspace_name" json:"workspace_name"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisioner(ctx context.Context, arg GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerParams) ([]GetProvisionerJobsByOrganizationAndStatusWithQueuePositionAndProvisionerRow, error) {
|
||||
@ -6337,6 +6365,12 @@ func (q *sqlQuerier) GetProvisionerJobsByOrganizationAndStatusWithQueuePositionA
|
||||
&i.QueuePosition,
|
||||
&i.QueueSize,
|
||||
pq.Array(&i.AvailableWorkers),
|
||||
&i.TemplateVersionName,
|
||||
&i.TemplateID,
|
||||
&i.TemplateName,
|
||||
&i.TemplateDisplayName,
|
||||
&i.WorkspaceID,
|
||||
&i.WorkspaceName,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -130,13 +130,29 @@ SELECT
|
||||
AND pj.organization_id = pd.organization_id
|
||||
AND pj.provisioner = ANY(pd.provisioners)
|
||||
AND provisioner_tagset_contains(pd.tags, pj.tags)
|
||||
) AS available_workers
|
||||
) AS available_workers,
|
||||
-- Include template and workspace information.
|
||||
COALESCE(tv.name, '') AS template_version_name,
|
||||
t.id AS template_id,
|
||||
COALESCE(t.name, '') AS template_name,
|
||||
COALESCE(t.display_name, '') AS template_display_name,
|
||||
w.id AS workspace_id,
|
||||
COALESCE(w.name, '') AS workspace_name
|
||||
FROM
|
||||
provisioner_jobs pj
|
||||
LEFT JOIN
|
||||
queue_position qp ON qp.id = pj.id
|
||||
LEFT JOIN
|
||||
queue_size qs ON TRUE
|
||||
LEFT JOIN
|
||||
workspace_builds wb ON wb.id = CASE WHEN pj.input ? 'workspace_build_id' THEN (pj.input->>'workspace_build_id')::uuid END
|
||||
LEFT JOIN
|
||||
workspaces w ON wb.workspace_id = w.id
|
||||
LEFT JOIN
|
||||
-- We should always have a template version, either explicitly or implicitly via workspace build.
|
||||
template_versions tv ON tv.id = CASE WHEN pj.input ? 'template_version_id' THEN (pj.input->>'template_version_id')::uuid ELSE wb.template_version_id END
|
||||
LEFT JOIN
|
||||
templates t ON tv.template_id = t.id
|
||||
WHERE
|
||||
(sqlc.narg('organization_id')::uuid IS NULL OR pj.organization_id = @organization_id)
|
||||
AND (COALESCE(array_length(@ids::uuid[], 1), 0) = 0 OR pj.id = ANY(@ids::uuid[]))
|
||||
@ -144,7 +160,13 @@ WHERE
|
||||
GROUP BY
|
||||
pj.id,
|
||||
qp.queue_position,
|
||||
qs.count
|
||||
qs.count,
|
||||
tv.name,
|
||||
t.id,
|
||||
t.name,
|
||||
t.display_name,
|
||||
w.id,
|
||||
w.name
|
||||
ORDER BY
|
||||
pj.created_at DESC
|
||||
LIMIT
|
||||
|
@ -388,6 +388,16 @@ func convertProvisionerJobWithQueuePosition(pj database.GetProvisionerJobsByOrga
|
||||
QueueSize: pj.QueueSize,
|
||||
})
|
||||
job.AvailableWorkers = pj.AvailableWorkers
|
||||
job.Metadata = &codersdk.ProvisionerJobMetadata{
|
||||
TemplateVersionName: pj.TemplateVersionName,
|
||||
TemplateID: pj.TemplateID.UUID,
|
||||
TemplateName: pj.TemplateName,
|
||||
TemplateDisplayName: pj.TemplateDisplayName,
|
||||
WorkspaceName: pj.WorkspaceName,
|
||||
}
|
||||
if pj.WorkspaceID.Valid {
|
||||
job.Metadata.WorkspaceID = &pj.WorkspaceID.UUID
|
||||
}
|
||||
return job
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
@ -72,13 +73,45 @@ func TestProvisionerJobs(t *testing.T) {
|
||||
|
||||
t.Run("Single", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Run("Workspace", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
// Note this calls the single job endpoint.
|
||||
job2, err := templateAdminClient.OrganizationProvisionerJob(ctx, owner.OrganizationID, job.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, job.ID, job2.ID)
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
// Note this calls the single job endpoint.
|
||||
job2, err := templateAdminClient.OrganizationProvisionerJob(ctx, owner.OrganizationID, job.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, job.ID, job2.ID)
|
||||
|
||||
// Verify that job metadata is correct.
|
||||
assert.Equal(t, job2.Metadata, &codersdk.ProvisionerJobMetadata{
|
||||
TemplateVersionName: version.Name,
|
||||
TemplateID: template.ID,
|
||||
TemplateName: template.Name,
|
||||
TemplateDisplayName: template.DisplayName,
|
||||
WorkspaceID: &w.ID,
|
||||
WorkspaceName: w.Name,
|
||||
})
|
||||
})
|
||||
})
|
||||
t.Run("Template Import", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("OK", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
// Note this calls the single job endpoint.
|
||||
job2, err := templateAdminClient.OrganizationProvisionerJob(ctx, owner.OrganizationID, version.Job.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, version.Job.ID, job2.ID)
|
||||
|
||||
// Verify that job metadata is correct.
|
||||
assert.Equal(t, job2.Metadata, &codersdk.ProvisionerJobMetadata{
|
||||
TemplateVersionName: version.Name,
|
||||
TemplateID: template.ID,
|
||||
TemplateName: template.Name,
|
||||
TemplateDisplayName: template.DisplayName,
|
||||
})
|
||||
})
|
||||
})
|
||||
t.Run("Missing", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
Reference in New Issue
Block a user