diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 3d4ae52e99..dbace5445f 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -5605,6 +5605,82 @@ const docTemplate = `{ } } }, + "/templateversions/{templateversion}/presets": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Templates" + ], + "summary": "Get template version presets", + "operationId": "get-template-version-presets", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Template version ID", + "name": "templateversion", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.Preset" + } + } + } + } + } + }, + "/templateversions/{templateversion}/presets/parameters": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Templates" + ], + "summary": "Get template version preset parameters", + "operationId": "get-template-version-preset-parameters", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Template version ID", + "name": "templateversion", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.PresetParameter" + } + } + } + } + } + }, "/templateversions/{templateversion}/resources": { "get": { "security": [ @@ -12924,6 +13000,31 @@ const docTemplate = `{ } } }, + "codersdk.Preset": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "codersdk.PresetParameter": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "presetID": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "codersdk.PrometheusConfig": { "type": "object", "properties": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index c431f8eca5..31dd166505 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -4951,6 +4951,74 @@ } } }, + "/templateversions/{templateversion}/presets": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Templates"], + "summary": "Get template version presets", + "operationId": "get-template-version-presets", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Template version ID", + "name": "templateversion", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.Preset" + } + } + } + } + } + }, + "/templateversions/{templateversion}/presets/parameters": { + "get": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "produces": ["application/json"], + "tags": ["Templates"], + "summary": "Get template version preset parameters", + "operationId": "get-template-version-preset-parameters", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Template version ID", + "name": "templateversion", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.PresetParameter" + } + } + } + } + } + }, "/templateversions/{templateversion}/resources": { "get": { "security": [ @@ -11661,6 +11729,31 @@ } } }, + "codersdk.Preset": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "codersdk.PresetParameter": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "presetID": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "codersdk.PrometheusConfig": { "type": "object", "properties": { diff --git a/coderd/coderd.go b/coderd/coderd.go index be55879738..d64e27f549 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1057,6 +1057,10 @@ func New(options *Options) *API { r.Get("/rich-parameters", api.templateVersionRichParameters) r.Get("/external-auth", api.templateVersionExternalAuth) r.Get("/variables", api.templateVersionVariables) + r.Route("/presets", func(r chi.Router) { + r.Get("/", api.templateVersionPresets) + r.Get("/parameters", api.templateVersionPresetParameters) + }) r.Get("/resources", api.templateVersionResources) r.Get("/logs", api.templateVersionLogs) r.Route("/dry-run", func(r chi.Router) { diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 28f8ee618b..689ebea74b 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1930,21 +1930,21 @@ func (q *querier) GetParameterSchemasByJobID(ctx context.Context, jobID uuid.UUI return q.db.GetParameterSchemasByJobID(ctx, jobID) } -func (q *querier) GetPresetByWorkspaceBuildID(ctx context.Context, workspaceID uuid.UUID) (database.GetPresetByWorkspaceBuildIDRow, error) { +func (q *querier) GetPresetByWorkspaceBuildID(ctx context.Context, workspaceID uuid.UUID) (database.TemplateVersionPreset, error) { // TODO (sasswart): Double check when to and not to call .InOrg? // TODO (sasswart): it makes sense to me that a caller can read a preset if they can read the template, but double check this. // TODO (sasswart): apply these todos to GetPresetParametersByPresetID and GetPresetsByTemplateVersionID. if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTemplate); err != nil { - return database.GetPresetByWorkspaceBuildIDRow{}, err + return database.TemplateVersionPreset{}, err } return q.db.GetPresetByWorkspaceBuildID(ctx, workspaceID) } -func (q *querier) GetPresetParametersByPresetID(ctx context.Context, templateVersionPresetID uuid.UUID) ([]database.GetPresetParametersByPresetIDRow, error) { +func (q *querier) GetPresetParametersByTemplateVersionID(ctx context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionPresetParameter, error) { if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceTemplate); err != nil { return nil, err } - return q.db.GetPresetParametersByPresetID(ctx, templateVersionPresetID) + return q.db.GetPresetParametersByTemplateVersionID(ctx, templateVersionID) } func (q *querier) GetPresetsByTemplateVersionID(ctx context.Context, templateVersionID uuid.UUID) ([]database.GetPresetsByTemplateVersionIDRow, error) { diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index dcfed4065c..a502af7f3a 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -3745,6 +3745,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { TemplateVersionID: templateVersion.ID, Name: "test", }) + require.NoError(s.T(), err) workspace := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ OrganizationID: org.ID, OwnerID: user.ID, @@ -3760,11 +3761,11 @@ func (s *MethodTestSuite) TestSystemFunctions() { InitiatorID: user.ID, JobID: job.ID, }) + _, err = db.GetPresetByWorkspaceBuildID(context.Background(), workspaceBuild.ID) require.NoError(s.T(), err) - db.GetPresetByWorkspaceBuildID(context.Background(), workspaceBuild.ID) check.Args(workspaceBuild.ID).Asserts(rbac.ResourceTemplate, policy.ActionRead) })) - s.Run("GetPresetParametersByPresetID", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetPresetParametersByTemplateVersionID", s.Subtest(func(db database.Store, check *expects) { org := dbgen.Organization(s.T(), db, database.Organization{}) user := dbgen.User(s.T(), db, database.User{}) template := dbgen.Template(s.T(), db, database.Template{ @@ -3776,31 +3777,17 @@ func (s *MethodTestSuite) TestSystemFunctions() { OrganizationID: org.ID, CreatedBy: user.ID, }) - workspace := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - OrganizationID: org.ID, - OwnerID: user.ID, - TemplateID: template.ID, - }) - job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ - OrganizationID: org.ID, - }) - workspaceBuild := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ - WorkspaceID: workspace.ID, - TemplateVersionID: templateVersion.ID, - InitiatorID: user.ID, - JobID: job.ID, - }) _, err := db.InsertPreset(context.Background(), database.InsertPresetParams{ - TemplateVersionID: workspaceBuild.TemplateVersionID, + TemplateVersionID: templateVersion.ID, Name: "test", }) require.NoError(s.T(), err) preset, err := db.InsertPreset(context.Background(), database.InsertPresetParams{ - TemplateVersionID: workspaceBuild.TemplateVersionID, + TemplateVersionID: templateVersion.ID, Name: "test", }) require.NoError(s.T(), err) - db.GetPresetParametersByPresetID(context.Background(), preset.ID) + db.GetPresetParametersByTemplateVersionID(context.Background(), templateVersion.ID) check.Args(preset.ID).Asserts(rbac.ResourceTemplate, policy.ActionRead) })) s.Run("GetPresetsByTemplateVersionID", s.Subtest(func(db database.Store, check *expects) { diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 79730f9e04..cfd360f740 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -314,6 +314,10 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil Deadline: takeFirst(orig.Deadline, dbtime.Now().Add(time.Hour)), MaxDeadline: takeFirst(orig.MaxDeadline, time.Time{}), Reason: takeFirst(orig.Reason, database.BuildReasonInitiator), + TemplateVersionPresetID: takeFirst(orig.TemplateVersionPresetID, uuid.NullUUID{ + UUID: uuid.UUID{}, + Valid: false, + }), }) if err != nil { return err diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 906cdf1a6f..f95306702d 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -3780,7 +3780,7 @@ func (q *FakeQuerier) GetParameterSchemasByJobID(_ context.Context, jobID uuid.U return parameters, nil } -func (q *FakeQuerier) GetPresetByWorkspaceBuildID(_ context.Context, workspaceBuildID uuid.UUID) (database.GetPresetByWorkspaceBuildIDRow, error) { +func (q *FakeQuerier) GetPresetByWorkspaceBuildID(_ context.Context, workspaceBuildID uuid.UUID) (database.TemplateVersionPreset, error) { q.mutex.RLock() defer q.mutex.RUnlock() @@ -3790,31 +3790,35 @@ func (q *FakeQuerier) GetPresetByWorkspaceBuildID(_ context.Context, workspaceBu } for _, preset := range q.presets { if preset.TemplateVersionID == workspaceBuild.TemplateVersionID { - return database.GetPresetByWorkspaceBuildIDRow{ - ID: preset.ID, - Name: preset.Name, - CreatedAt: preset.CreatedAt, - }, nil + return preset, nil } } } - return database.GetPresetByWorkspaceBuildIDRow{}, sql.ErrNoRows + return database.TemplateVersionPreset{}, sql.ErrNoRows } -func (q *FakeQuerier) GetPresetParametersByPresetID(_ context.Context, templateVersionPresetID uuid.UUID) ([]database.GetPresetParametersByPresetIDRow, error) { +func (q *FakeQuerier) GetPresetParametersByTemplateVersionID(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionPresetParameter, error) { q.mutex.RLock() defer q.mutex.RUnlock() - parameters := make([]database.GetPresetParametersByPresetIDRow, 0) + presets := make([]database.TemplateVersionPreset, 0) + parameters := make([]database.TemplateVersionPresetParameter, 0) + for _, preset := range q.presets { + if preset.TemplateVersionID != templateVersionID { + continue + } + presets = append(presets, preset) + } for _, parameter := range q.presetParameters { - if parameter.TemplateVersionPresetID == templateVersionPresetID { - parameters = append(parameters, database.GetPresetParametersByPresetIDRow{ - ID: parameter.ID, - Name: parameter.Name, - Value: parameter.Value, - }) + for _, preset := range presets { + if parameter.TemplateVersionPresetID != preset.ID { + continue + } + parameters = append(parameters, parameter) + break } } + return parameters, nil } diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index 62de68c613..7145e46052 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -980,17 +980,17 @@ func (m queryMetricsStore) GetParameterSchemasByJobID(ctx context.Context, jobID return schemas, err } -func (m queryMetricsStore) GetPresetByWorkspaceBuildID(ctx context.Context, workspaceBuildID uuid.UUID) (database.GetPresetByWorkspaceBuildIDRow, error) { +func (m queryMetricsStore) GetPresetByWorkspaceBuildID(ctx context.Context, workspaceBuildID uuid.UUID) (database.TemplateVersionPreset, error) { start := time.Now() r0, r1 := m.s.GetPresetByWorkspaceBuildID(ctx, workspaceBuildID) m.queryLatencies.WithLabelValues("GetPresetByWorkspaceBuildID").Observe(time.Since(start).Seconds()) return r0, r1 } -func (m queryMetricsStore) GetPresetParametersByPresetID(ctx context.Context, templateVersionPresetID uuid.UUID) ([]database.GetPresetParametersByPresetIDRow, error) { +func (m queryMetricsStore) GetPresetParametersByTemplateVersionID(ctx context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionPresetParameter, error) { start := time.Now() - r0, r1 := m.s.GetPresetParametersByPresetID(ctx, templateVersionPresetID) - m.queryLatencies.WithLabelValues("GetPresetParametersByPresetID").Observe(time.Since(start).Seconds()) + r0, r1 := m.s.GetPresetParametersByTemplateVersionID(ctx, templateVersionID) + m.queryLatencies.WithLabelValues("GetPresetParametersByTemplateVersionID").Observe(time.Since(start).Seconds()) return r0, r1 } diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 19206b2411..525dad9388 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -2017,10 +2017,10 @@ func (mr *MockStoreMockRecorder) GetParameterSchemasByJobID(ctx, jobID any) *gom } // GetPresetByWorkspaceBuildID mocks base method. -func (m *MockStore) GetPresetByWorkspaceBuildID(arg0 context.Context, arg1 uuid.UUID) (database.GetPresetByWorkspaceBuildIDRow, error) { +func (m *MockStore) GetPresetByWorkspaceBuildID(arg0 context.Context, arg1 uuid.UUID) (database.TemplateVersionPreset, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetPresetByWorkspaceBuildID", arg0, arg1) - ret0, _ := ret[0].(database.GetPresetByWorkspaceBuildIDRow) + ret0, _ := ret[0].(database.TemplateVersionPreset) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -2031,19 +2031,19 @@ func (mr *MockStoreMockRecorder) GetPresetByWorkspaceBuildID(arg0, arg1 any) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPresetByWorkspaceBuildID", reflect.TypeOf((*MockStore)(nil).GetPresetByWorkspaceBuildID), arg0, arg1) } -// GetPresetParametersByPresetID mocks base method. -func (m *MockStore) GetPresetParametersByPresetID(arg0 context.Context, arg1 uuid.UUID) ([]database.GetPresetParametersByPresetIDRow, error) { +// GetPresetParametersByTemplateVersionID mocks base method. +func (m *MockStore) GetPresetParametersByTemplateVersionID(arg0 context.Context, arg1 uuid.UUID) ([]database.TemplateVersionPresetParameter, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPresetParametersByPresetID", arg0, arg1) - ret0, _ := ret[0].([]database.GetPresetParametersByPresetIDRow) + ret := m.ctrl.Call(m, "GetPresetParametersByTemplateVersionID", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateVersionPresetParameter) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetPresetParametersByPresetID indicates an expected call of GetPresetParametersByPresetID. -func (mr *MockStoreMockRecorder) GetPresetParametersByPresetID(arg0, arg1 any) *gomock.Call { +// GetPresetParametersByTemplateVersionID indicates an expected call of GetPresetParametersByTemplateVersionID. +func (mr *MockStoreMockRecorder) GetPresetParametersByTemplateVersionID(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPresetParametersByPresetID", reflect.TypeOf((*MockStore)(nil).GetPresetParametersByPresetID), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPresetParametersByTemplateVersionID", reflect.TypeOf((*MockStore)(nil).GetPresetParametersByTemplateVersionID), arg0, arg1) } // GetPresetsByTemplateVersionID mocks base method. diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 6b35e6ea92..0cb5990536 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -202,8 +202,8 @@ type sqlcQuerier interface { GetOrganizations(ctx context.Context, arg GetOrganizationsParams) ([]Organization, error) GetOrganizationsByUserID(ctx context.Context, userID uuid.UUID) ([]Organization, error) GetParameterSchemasByJobID(ctx context.Context, jobID uuid.UUID) ([]ParameterSchema, error) - GetPresetByWorkspaceBuildID(ctx context.Context, workspaceBuildID uuid.UUID) (GetPresetByWorkspaceBuildIDRow, error) - GetPresetParametersByPresetID(ctx context.Context, templateVersionPresetID uuid.UUID) ([]GetPresetParametersByPresetIDRow, error) + GetPresetByWorkspaceBuildID(ctx context.Context, workspaceBuildID uuid.UUID) (TemplateVersionPreset, error) + GetPresetParametersByTemplateVersionID(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionPresetParameter, error) GetPresetsByTemplateVersionID(ctx context.Context, templateVersionID uuid.UUID) ([]GetPresetsByTemplateVersionIDRow, error) GetPreviousTemplateVersion(ctx context.Context, arg GetPreviousTemplateVersionParams) (TemplateVersion, error) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index c8150d74f7..7f07b09f9d 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -5397,56 +5397,51 @@ func (q *sqlQuerier) GetParameterSchemasByJobID(ctx context.Context, jobID uuid. const getPresetByWorkspaceBuildID = `-- name: GetPresetByWorkspaceBuildID :one SELECT - template_version_presets.id, - template_version_presets.name, - template_version_presets.created_at + template_version_presets.id, template_version_presets.template_version_id, template_version_presets.name, template_version_presets.created_at FROM - workspace_builds - INNER JOIN template_version_presets ON workspace_builds.template_version_preset_id = template_version_presets.id + template_version_presets + INNER JOIN workspace_builds ON workspace_builds.template_version_preset_id = template_version_presets.id WHERE workspace_builds.id = $1 ` -type GetPresetByWorkspaceBuildIDRow struct { - ID uuid.UUID `db:"id" json:"id"` - Name string `db:"name" json:"name"` - CreatedAt time.Time `db:"created_at" json:"created_at"` -} - -func (q *sqlQuerier) GetPresetByWorkspaceBuildID(ctx context.Context, workspaceBuildID uuid.UUID) (GetPresetByWorkspaceBuildIDRow, error) { +func (q *sqlQuerier) GetPresetByWorkspaceBuildID(ctx context.Context, workspaceBuildID uuid.UUID) (TemplateVersionPreset, error) { row := q.db.QueryRowContext(ctx, getPresetByWorkspaceBuildID, workspaceBuildID) - var i GetPresetByWorkspaceBuildIDRow - err := row.Scan(&i.ID, &i.Name, &i.CreatedAt) + var i TemplateVersionPreset + err := row.Scan( + &i.ID, + &i.TemplateVersionID, + &i.Name, + &i.CreatedAt, + ) return i, err } -const getPresetParametersByPresetID = `-- name: GetPresetParametersByPresetID :many +const getPresetParametersByTemplateVersionID = `-- name: GetPresetParametersByTemplateVersionID :many SELECT - id, - name, - value + template_version_preset_parameters.id, template_version_preset_parameters.template_version_preset_id, template_version_preset_parameters.name, template_version_preset_parameters.value FROM template_version_preset_parameters + INNER JOIN template_version_presets ON template_version_preset_parameters.template_version_preset_id = template_version_presets.id WHERE - template_version_preset_id = $1 + template_version_presets.template_version_id = $1 ` -type GetPresetParametersByPresetIDRow struct { - ID uuid.UUID `db:"id" json:"id"` - Name string `db:"name" json:"name"` - Value string `db:"value" json:"value"` -} - -func (q *sqlQuerier) GetPresetParametersByPresetID(ctx context.Context, templateVersionPresetID uuid.UUID) ([]GetPresetParametersByPresetIDRow, error) { - rows, err := q.db.QueryContext(ctx, getPresetParametersByPresetID, templateVersionPresetID) +func (q *sqlQuerier) GetPresetParametersByTemplateVersionID(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionPresetParameter, error) { + rows, err := q.db.QueryContext(ctx, getPresetParametersByTemplateVersionID, templateVersionID) if err != nil { return nil, err } defer rows.Close() - var items []GetPresetParametersByPresetIDRow + var items []TemplateVersionPresetParameter for rows.Next() { - var i GetPresetParametersByPresetIDRow - if err := rows.Scan(&i.ID, &i.Name, &i.Value); err != nil { + var i TemplateVersionPresetParameter + if err := rows.Scan( + &i.ID, + &i.TemplateVersionPresetID, + &i.Name, + &i.Value, + ); err != nil { return nil, err } items = append(items, i) @@ -15020,26 +15015,28 @@ INSERT INTO provisioner_state, deadline, max_deadline, - reason + reason, + template_version_preset_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) ` type InsertWorkspaceBuildParams struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"` - TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"` - BuildNumber int32 `db:"build_number" json:"build_number"` - Transition WorkspaceTransition `db:"transition" json:"transition"` - InitiatorID uuid.UUID `db:"initiator_id" json:"initiator_id"` - JobID uuid.UUID `db:"job_id" json:"job_id"` - ProvisionerState []byte `db:"provisioner_state" json:"provisioner_state"` - Deadline time.Time `db:"deadline" json:"deadline"` - MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"` - Reason BuildReason `db:"reason" json:"reason"` + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"` + TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"` + BuildNumber int32 `db:"build_number" json:"build_number"` + Transition WorkspaceTransition `db:"transition" json:"transition"` + InitiatorID uuid.UUID `db:"initiator_id" json:"initiator_id"` + JobID uuid.UUID `db:"job_id" json:"job_id"` + ProvisionerState []byte `db:"provisioner_state" json:"provisioner_state"` + Deadline time.Time `db:"deadline" json:"deadline"` + MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"` + Reason BuildReason `db:"reason" json:"reason"` + TemplateVersionPresetID uuid.NullUUID `db:"template_version_preset_id" json:"template_version_preset_id"` } func (q *sqlQuerier) InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspaceBuildParams) error { @@ -15057,6 +15054,7 @@ func (q *sqlQuerier) InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspa arg.Deadline, arg.MaxDeadline, arg.Reason, + arg.TemplateVersionPresetID, ) return err } diff --git a/coderd/database/queries/presets.sql b/coderd/database/queries/presets.sql index 469591f8a4..883d6c4214 100644 --- a/coderd/database/queries/presets.sql +++ b/coderd/database/queries/presets.sql @@ -25,21 +25,18 @@ WHERE -- name: GetPresetByWorkspaceBuildID :one SELECT - template_version_presets.id, - template_version_presets.name, - template_version_presets.created_at + template_version_presets.* FROM - workspace_builds - INNER JOIN template_version_presets ON workspace_builds.template_version_preset_id = template_version_presets.id + template_version_presets + INNER JOIN workspace_builds ON workspace_builds.template_version_preset_id = template_version_presets.id WHERE workspace_builds.id = @workspace_build_id; --- name: GetPresetParametersByPresetID :many +-- name: GetPresetParametersByTemplateVersionID :many SELECT - id, - name, - value + template_version_preset_parameters.* FROM template_version_preset_parameters + INNER JOIN template_version_presets ON template_version_preset_parameters.template_version_preset_id = template_version_presets.id WHERE - template_version_preset_id = @template_version_preset_id; + template_version_presets.template_version_id = @template_version_id; diff --git a/coderd/database/queries/workspacebuilds.sql b/coderd/database/queries/workspacebuilds.sql index 7050b61644..da349fa144 100644 --- a/coderd/database/queries/workspacebuilds.sql +++ b/coderd/database/queries/workspacebuilds.sql @@ -120,10 +120,11 @@ INSERT INTO provisioner_state, deadline, max_deadline, - reason + reason, + template_version_preset_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13); + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14); -- name: UpdateWorkspaceBuildCostByID :exec UPDATE diff --git a/coderd/presets.go b/coderd/presets.go new file mode 100644 index 0000000000..83cade37d3 --- /dev/null +++ b/coderd/presets.go @@ -0,0 +1,76 @@ +package coderd + +import ( + "net/http" + + "github.com/coder/coder/v2/coderd/httpapi" + "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/codersdk" +) + +// @Summary Get template version presets +// @ID get-template-version-presets +// @Security CoderSessionToken +// @Produce json +// @Tags Templates +// @Param templateversion path string true "Template version ID" format(uuid) +// @Success 200 {array} codersdk.Preset +// @Router /templateversions/{templateversion}/presets [get] +func (api *API) templateVersionPresets(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + templateVersion := httpmw.TemplateVersionParam(r) + + presets, err := api.Database.GetPresetsByTemplateVersionID(ctx, templateVersion.ID) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching template version presets.", + Detail: err.Error(), + }) + return + } + + var res []codersdk.Preset + for _, preset := range presets { + res = append(res, codersdk.Preset{ + ID: preset.ID, + Name: preset.Name, + }) + } + + httpapi.Write(ctx, rw, http.StatusOK, res) +} + +// @Summary Get template version preset parameters +// @ID get-template-version-preset-parameters +// @Security CoderSessionToken +// @Produce json +// @Tags Templates +// @Param templateversion path string true "Template version ID" format(uuid) +// @Success 200 {array} codersdk.PresetParameter +// @Router /templateversions/{templateversion}/presets/parameters [get] +func (api *API) templateVersionPresetParameters(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + templateVersion := httpmw.TemplateVersionParam(r) + + // TODO (sasswart): Test case: what if a user tries to read presets or preset parameters from a different org? + // TODO (sasswart): Do a prelim auth check here. + + presetParams, err := api.Database.GetPresetParametersByTemplateVersionID(ctx, templateVersion.ID) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching template version presets.", + Detail: err.Error(), + }) + } + + var res []codersdk.PresetParameter + for _, presetParam := range presetParams { + res = append(res, codersdk.PresetParameter{ + PresetID: presetParam.ID, + Name: presetParam.Name, + Value: presetParam.Value, + }) + } + + httpapi.Write(ctx, rw, http.StatusOK, res) +} diff --git a/codersdk/presets.go b/codersdk/presets.go new file mode 100644 index 0000000000..cd724a979a --- /dev/null +++ b/codersdk/presets.go @@ -0,0 +1,50 @@ +package codersdk + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/google/uuid" + "golang.org/x/xerrors" +) + +type Preset struct { + ID uuid.UUID + Name string +} + +type PresetParameter struct { + PresetID uuid.UUID + Name string + Value string +} + +// TemplateVersionPresets returns the presets associated with a template version. +func (c *Client) TemplateVersionPresets(ctx context.Context, templateVersionID uuid.UUID) ([]Preset, error) { + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/presets", templateVersionID), nil) + if err != nil { + return nil, xerrors.Errorf("do request: %w", err) + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return nil, ReadBodyAsError(res) + } + var presets []Preset + return presets, json.NewDecoder(res.Body).Decode(&presets) +} + +// TemplateVersionPresetParameters returns the parameters associated with the given presets. +func (c *Client) TemplateVersionPresetParameters(ctx context.Context, templateVersionID uuid.UUID) ([]PresetParameter, error) { + res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/presets/parameters", templateVersionID), nil) + if err != nil { + return nil, xerrors.Errorf("do request: %w", err) + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return nil, ReadBodyAsError(res) + } + var parameters []PresetParameter + return parameters, json.NewDecoder(res.Body).Decode(¶meters) +} diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 1af6ac7285..1b3adb8f14 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -4427,6 +4427,40 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith | `address` | [serpent.HostPort](#serpenthostport) | false | | | | `enable` | boolean | false | | | +## codersdk.Preset + +```json +{ + "id": "string", + "name": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|--------|--------|----------|--------------|-------------| +| `id` | string | false | | | +| `name` | string | false | | | + +## codersdk.PresetParameter + +```json +{ + "name": "string", + "presetID": "string", + "value": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|------------|--------|----------|--------------|-------------| +| `name` | string | false | | | +| `presetID` | string | false | | | +| `value` | string | false | | | + ## codersdk.PrometheusConfig ```json diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md index 6378c5f233..a0b9d4b430 100644 --- a/docs/reference/api/templates.md +++ b/docs/reference/api/templates.md @@ -2575,6 +2575,108 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/p To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Get template version presets + +### Code samples + +```shell +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/presets \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /templateversions/{templateversion}/presets` + +### Parameters + +| Name | In | Type | Required | Description | +|-------------------|------|--------------|----------|---------------------| +| `templateversion` | path | string(uuid) | true | Template version ID | + +### Example responses + +> 200 Response + +```json +[ + { + "id": "string", + "name": "string" + } +] +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|---------------------------------------------------------|-------------|-------------------------------------------------------| +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.Preset](schemas.md#codersdkpreset) | + +