mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
feat: Add basic support for rich parameters to coderd and provisionerd (#5710)
This commit is contained in:
38
coderd/apidoc/docs.go
generated
38
coderd/apidoc/docs.go
generated
@ -2516,6 +2516,44 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/rich-parameters": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Templates"
|
||||
],
|
||||
"summary": "Get rich parameters by template version",
|
||||
"operationId": "get-rich-parameters-by-template-version",
|
||||
"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/parameter.ComputedValue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/schema": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
34
coderd/apidoc/swagger.json
generated
34
coderd/apidoc/swagger.json
generated
@ -2216,6 +2216,40 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/rich-parameters": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Templates"],
|
||||
"summary": "Get rich parameters by template version",
|
||||
"operationId": "get-rich-parameters-by-template-version",
|
||||
"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/parameter.ComputedValue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/templateversions/{templateversion}/schema": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
@ -435,6 +435,7 @@ func New(options *Options) *API {
|
||||
r.Patch("/cancel", api.patchCancelTemplateVersion)
|
||||
r.Get("/schema", api.templateVersionSchema)
|
||||
r.Get("/parameters", api.templateVersionParameters)
|
||||
r.Get("/rich-parameters", api.templateVersionRichParameters)
|
||||
r.Get("/resources", api.templateVersionResources)
|
||||
r.Get("/logs", api.templateVersionLogs)
|
||||
r.Route("/dry-run", func(r chi.Router) {
|
||||
|
@ -177,6 +177,10 @@ func AGPLRoutes(a *AuthTester) (map[string]string, map[string]RouteCheck) {
|
||||
AssertAction: rbac.ActionRead,
|
||||
AssertObject: rbac.ResourceTemplate.InOrg(a.Template.OrganizationID),
|
||||
},
|
||||
"GET:/api/v2/templateversions/{templateversion}/rich-parameters": {
|
||||
AssertAction: rbac.ActionRead,
|
||||
AssertObject: rbac.ResourceTemplate.InOrg(a.Template.OrganizationID),
|
||||
},
|
||||
"GET:/api/v2/templateversions/{templateversion}/resources": {
|
||||
AssertAction: rbac.ActionRead,
|
||||
AssertObject: rbac.ResourceTemplate.InOrg(a.Template.OrganizationID),
|
||||
|
@ -111,10 +111,12 @@ type data struct {
|
||||
provisionerJobs []database.ProvisionerJob
|
||||
replicas []database.Replica
|
||||
templateVersions []database.TemplateVersion
|
||||
templateVersionParameters []database.TemplateVersionParameter
|
||||
templates []database.Template
|
||||
workspaceAgents []database.WorkspaceAgent
|
||||
workspaceApps []database.WorkspaceApp
|
||||
workspaceBuilds []database.WorkspaceBuild
|
||||
workspaceBuildParameters []database.WorkspaceBuildParameter
|
||||
workspaceResourceMetadata []database.WorkspaceResourceMetadatum
|
||||
workspaceResources []database.WorkspaceResource
|
||||
workspaces []database.Workspace
|
||||
@ -1365,6 +1367,20 @@ func (q *fakeQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(_ context.Con
|
||||
return database.WorkspaceBuild{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetWorkspaceBuildParameters(_ context.Context, workspaceBuildID uuid.UUID) ([]database.WorkspaceBuildParameter, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
params := make([]database.WorkspaceBuildParameter, 0)
|
||||
for _, param := range params {
|
||||
if param.WorkspaceBuildID != workspaceBuildID {
|
||||
continue
|
||||
}
|
||||
params = append(params, param)
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetWorkspaceBuildsCreatedAfter(_ context.Context, after time.Time) ([]database.WorkspaceBuild, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
@ -1656,6 +1672,20 @@ func (q *fakeQuerier) GetTemplateVersionByTemplateIDAndName(_ context.Context, a
|
||||
return database.TemplateVersion{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetTemplateVersionParameters(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionParameter, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
parameters := make([]database.TemplateVersionParameter, 0)
|
||||
for _, param := range q.templateVersionParameters {
|
||||
if param.TemplateVersionID != templateVersionID {
|
||||
continue
|
||||
}
|
||||
parameters = append(parameters, param)
|
||||
}
|
||||
return parameters, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) GetTemplateVersionByOrganizationAndName(_ context.Context, arg database.GetTemplateVersionByOrganizationAndNameParams) (database.TemplateVersion, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
@ -2398,6 +2428,28 @@ func (q *fakeQuerier) InsertTemplateVersion(_ context.Context, arg database.Inse
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) InsertTemplateVersionParameter(_ context.Context, arg database.InsertTemplateVersionParameterParams) (database.TemplateVersionParameter, error) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
//nolint:gosimple
|
||||
param := database.TemplateVersionParameter{
|
||||
TemplateVersionID: arg.TemplateVersionID,
|
||||
Name: arg.Name,
|
||||
Description: arg.Description,
|
||||
Type: arg.Type,
|
||||
Mutable: arg.Mutable,
|
||||
DefaultValue: arg.DefaultValue,
|
||||
Icon: arg.Icon,
|
||||
Options: arg.Options,
|
||||
ValidationRegex: arg.ValidationRegex,
|
||||
ValidationMin: arg.ValidationMin,
|
||||
ValidationMax: arg.ValidationMax,
|
||||
}
|
||||
q.templateVersionParameters = append(q.templateVersionParameters, param)
|
||||
return param, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) InsertProvisionerJobLogs(_ context.Context, arg database.InsertProvisionerJobLogsParams) ([]database.ProvisionerJobLog, error) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
@ -2723,6 +2775,20 @@ func (q *fakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.Inser
|
||||
return workspaceBuild, nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) InsertWorkspaceBuildParameters(_ context.Context, arg database.InsertWorkspaceBuildParametersParams) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
for index, name := range arg.Name {
|
||||
q.workspaceBuildParameters = append(q.workspaceBuildParameters, database.WorkspaceBuildParameter{
|
||||
WorkspaceBuildID: arg.WorkspaceBuildID,
|
||||
Name: name,
|
||||
Value: arg.Value[index],
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *fakeQuerier) InsertWorkspaceApp(_ context.Context, arg database.InsertWorkspaceAppParams) (database.WorkspaceApp, error) {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
56
coderd/database/dump.sql
generated
56
coderd/database/dump.sql
generated
@ -331,6 +331,40 @@ CREATE TABLE site_configs (
|
||||
value character varying(8192) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE template_version_parameters (
|
||||
template_version_id uuid NOT NULL,
|
||||
name text NOT NULL,
|
||||
description text NOT NULL,
|
||||
type text NOT NULL,
|
||||
mutable boolean NOT NULL,
|
||||
default_value text NOT NULL,
|
||||
icon text NOT NULL,
|
||||
options jsonb DEFAULT '[]'::jsonb NOT NULL,
|
||||
validation_regex text NOT NULL,
|
||||
validation_min integer NOT NULL,
|
||||
validation_max integer NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.name IS 'Parameter name';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.description IS 'Parameter description';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.type IS 'Parameter type';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.mutable IS 'Is parameter mutable?';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.default_value IS 'Default value';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.icon IS 'Icon';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.options IS 'Additional options';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.validation_regex IS 'Validation: regex pattern';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.validation_min IS 'Validation: minimum length of value';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.validation_max IS 'Validation: maximum length of value';
|
||||
|
||||
CREATE TABLE template_versions (
|
||||
id uuid NOT NULL,
|
||||
template_id uuid,
|
||||
@ -443,6 +477,16 @@ CREATE TABLE workspace_apps (
|
||||
external boolean DEFAULT false NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE workspace_build_parameters (
|
||||
workspace_build_id uuid NOT NULL,
|
||||
name text NOT NULL,
|
||||
value text NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN workspace_build_parameters.name IS 'Parameter name';
|
||||
|
||||
COMMENT ON COLUMN workspace_build_parameters.value IS 'Parameter value';
|
||||
|
||||
CREATE TABLE workspace_builds (
|
||||
id uuid NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
@ -578,6 +622,9 @@ ALTER TABLE ONLY provisioner_jobs
|
||||
ALTER TABLE ONLY site_configs
|
||||
ADD CONSTRAINT site_configs_key_key UNIQUE (key);
|
||||
|
||||
ALTER TABLE ONLY template_version_parameters
|
||||
ADD CONSTRAINT template_version_parameters_template_version_id_name_key UNIQUE (template_version_id, name);
|
||||
|
||||
ALTER TABLE ONLY template_versions
|
||||
ADD CONSTRAINT template_versions_pkey PRIMARY KEY (id);
|
||||
|
||||
@ -602,6 +649,9 @@ ALTER TABLE ONLY workspace_apps
|
||||
ALTER TABLE ONLY workspace_apps
|
||||
ADD CONSTRAINT workspace_apps_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY workspace_build_parameters
|
||||
ADD CONSTRAINT workspace_build_parameters_workspace_build_id_name_key UNIQUE (workspace_build_id, name);
|
||||
|
||||
ALTER TABLE ONLY workspace_builds
|
||||
ADD CONSTRAINT workspace_builds_job_id_key UNIQUE (job_id);
|
||||
|
||||
@ -697,6 +747,9 @@ ALTER TABLE ONLY provisioner_job_logs
|
||||
ALTER TABLE ONLY provisioner_jobs
|
||||
ADD CONSTRAINT provisioner_jobs_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY template_version_parameters
|
||||
ADD CONSTRAINT template_version_parameters_template_version_id_fkey FOREIGN KEY (template_version_id) REFERENCES template_versions(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY template_versions
|
||||
ADD CONSTRAINT template_versions_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT;
|
||||
|
||||
@ -721,6 +774,9 @@ ALTER TABLE ONLY workspace_agents
|
||||
ALTER TABLE ONLY workspace_apps
|
||||
ADD CONSTRAINT workspace_apps_agent_id_fkey FOREIGN KEY (agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY workspace_build_parameters
|
||||
ADD CONSTRAINT workspace_build_parameters_workspace_build_id_fkey FOREIGN KEY (workspace_build_id) REFERENCES workspace_builds(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY workspace_builds
|
||||
ADD CONSTRAINT workspace_builds_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE;
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
DROP TABLE template_version_parameters;
|
||||
|
||||
DROP TABLE workspace_build_parameters;
|
35
coderd/database/migrations/000089_rich_parameters.up.sql
Normal file
35
coderd/database/migrations/000089_rich_parameters.up.sql
Normal file
@ -0,0 +1,35 @@
|
||||
CREATE TABLE IF NOT EXISTS template_version_parameters (
|
||||
template_version_id uuid not null references template_versions (id) on delete cascade,
|
||||
name text not null,
|
||||
description text not null,
|
||||
type text not null,
|
||||
mutable boolean not null,
|
||||
default_value text not null,
|
||||
icon text not null,
|
||||
options jsonb not null default '[]'::jsonb,
|
||||
validation_regex text not null,
|
||||
validation_min integer not null,
|
||||
validation_max integer not null,
|
||||
unique (template_version_id, name)
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.name IS 'Parameter name';
|
||||
COMMENT ON COLUMN template_version_parameters.description IS 'Parameter description';
|
||||
COMMENT ON COLUMN template_version_parameters.type IS 'Parameter type';
|
||||
COMMENT ON COLUMN template_version_parameters.mutable IS 'Is parameter mutable?';
|
||||
COMMENT ON COLUMN template_version_parameters.default_value IS 'Default value';
|
||||
COMMENT ON COLUMN template_version_parameters.icon IS 'Icon';
|
||||
COMMENT ON COLUMN template_version_parameters.options IS 'Additional options';
|
||||
COMMENT ON COLUMN template_version_parameters.validation_regex IS 'Validation: regex pattern';
|
||||
COMMENT ON COLUMN template_version_parameters.validation_min IS 'Validation: minimum length of value';
|
||||
COMMENT ON COLUMN template_version_parameters.validation_max IS 'Validation: maximum length of value';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS workspace_build_parameters (
|
||||
workspace_build_id uuid not null references workspace_builds (id) on delete cascade,
|
||||
name text not null,
|
||||
value text not null,
|
||||
unique (workspace_build_id, name)
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN workspace_build_parameters.name IS 'Parameter name';
|
||||
COMMENT ON COLUMN workspace_build_parameters.value IS 'Parameter value';
|
@ -239,6 +239,8 @@ func TestMigrateUpWithFixtures(t *testing.T) {
|
||||
"group_members",
|
||||
"licenses",
|
||||
"replicas",
|
||||
"template_version_parameters",
|
||||
"workspace_build_parameters",
|
||||
}
|
||||
s := &tableStats{s: make(map[string]int)}
|
||||
|
||||
|
@ -612,6 +612,30 @@ type TemplateVersion struct {
|
||||
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
|
||||
}
|
||||
|
||||
type TemplateVersionParameter struct {
|
||||
TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"`
|
||||
// Parameter name
|
||||
Name string `db:"name" json:"name"`
|
||||
// Parameter description
|
||||
Description string `db:"description" json:"description"`
|
||||
// Parameter type
|
||||
Type string `db:"type" json:"type"`
|
||||
// Is parameter mutable?
|
||||
Mutable bool `db:"mutable" json:"mutable"`
|
||||
// Default value
|
||||
DefaultValue string `db:"default_value" json:"default_value"`
|
||||
// Icon
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
// Additional options
|
||||
Options json.RawMessage `db:"options" json:"options"`
|
||||
// Validation: regex pattern
|
||||
ValidationRegex string `db:"validation_regex" json:"validation_regex"`
|
||||
// Validation: minimum length of value
|
||||
ValidationMin int32 `db:"validation_min" json:"validation_min"`
|
||||
// Validation: maximum length of value
|
||||
ValidationMax int32 `db:"validation_max" json:"validation_max"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
Email string `db:"email" json:"email"`
|
||||
@ -713,6 +737,14 @@ type WorkspaceBuild struct {
|
||||
DailyCost int32 `db:"daily_cost" json:"daily_cost"`
|
||||
}
|
||||
|
||||
type WorkspaceBuildParameter struct {
|
||||
WorkspaceBuildID uuid.UUID `db:"workspace_build_id" json:"workspace_build_id"`
|
||||
// Parameter name
|
||||
Name string `db:"name" json:"name"`
|
||||
// Parameter value
|
||||
Value string `db:"value" json:"value"`
|
||||
}
|
||||
|
||||
type WorkspaceResource struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
|
@ -87,6 +87,7 @@ type sqlcQuerier interface {
|
||||
GetTemplateVersionByJobID(ctx context.Context, jobID uuid.UUID) (TemplateVersion, error)
|
||||
GetTemplateVersionByOrganizationAndName(ctx context.Context, arg GetTemplateVersionByOrganizationAndNameParams) (TemplateVersion, error)
|
||||
GetTemplateVersionByTemplateIDAndName(ctx context.Context, arg GetTemplateVersionByTemplateIDAndNameParams) (TemplateVersion, error)
|
||||
GetTemplateVersionParameters(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionParameter, error)
|
||||
GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UUID) ([]TemplateVersion, error)
|
||||
GetTemplateVersionsByTemplateID(ctx context.Context, arg GetTemplateVersionsByTemplateIDParams) ([]TemplateVersion, error)
|
||||
GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error)
|
||||
@ -117,6 +118,7 @@ type sqlcQuerier interface {
|
||||
GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (WorkspaceBuild, error)
|
||||
GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UUID) (WorkspaceBuild, error)
|
||||
GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx context.Context, arg GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams) (WorkspaceBuild, error)
|
||||
GetWorkspaceBuildParameters(ctx context.Context, workspaceBuildID uuid.UUID) ([]WorkspaceBuildParameter, error)
|
||||
GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg GetWorkspaceBuildsByWorkspaceIDParams) ([]WorkspaceBuild, error)
|
||||
GetWorkspaceBuildsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceBuild, error)
|
||||
GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (Workspace, error)
|
||||
@ -159,12 +161,14 @@ type sqlcQuerier interface {
|
||||
InsertReplica(ctx context.Context, arg InsertReplicaParams) (Replica, error)
|
||||
InsertTemplate(ctx context.Context, arg InsertTemplateParams) (Template, error)
|
||||
InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) (TemplateVersion, error)
|
||||
InsertTemplateVersionParameter(ctx context.Context, arg InsertTemplateVersionParameterParams) (TemplateVersionParameter, error)
|
||||
InsertUser(ctx context.Context, arg InsertUserParams) (User, error)
|
||||
InsertUserLink(ctx context.Context, arg InsertUserLinkParams) (UserLink, error)
|
||||
InsertWorkspace(ctx context.Context, arg InsertWorkspaceParams) (Workspace, error)
|
||||
InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspaceAgentParams) (WorkspaceAgent, error)
|
||||
InsertWorkspaceApp(ctx context.Context, arg InsertWorkspaceAppParams) (WorkspaceApp, error)
|
||||
InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspaceBuildParams) (WorkspaceBuild, error)
|
||||
InsertWorkspaceBuildParameters(ctx context.Context, arg InsertWorkspaceBuildParametersParams) error
|
||||
InsertWorkspaceResource(ctx context.Context, arg InsertWorkspaceResourceParams) (WorkspaceResource, error)
|
||||
InsertWorkspaceResourceMetadata(ctx context.Context, arg InsertWorkspaceResourceMetadataParams) ([]WorkspaceResourceMetadatum, error)
|
||||
ParameterValue(ctx context.Context, id uuid.UUID) (ParameterValue, error)
|
||||
|
@ -3542,6 +3542,121 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTemplateVersionParameters = `-- name: GetTemplateVersionParameters :many
|
||||
SELECT template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max FROM template_version_parameters WHERE template_version_id = $1
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetTemplateVersionParameters(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionParameter, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTemplateVersionParameters, templateVersionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TemplateVersionParameter
|
||||
for rows.Next() {
|
||||
var i TemplateVersionParameter
|
||||
if err := rows.Scan(
|
||||
&i.TemplateVersionID,
|
||||
&i.Name,
|
||||
&i.Description,
|
||||
&i.Type,
|
||||
&i.Mutable,
|
||||
&i.DefaultValue,
|
||||
&i.Icon,
|
||||
&i.Options,
|
||||
&i.ValidationRegex,
|
||||
&i.ValidationMin,
|
||||
&i.ValidationMax,
|
||||
); 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 insertTemplateVersionParameter = `-- name: InsertTemplateVersionParameter :one
|
||||
INSERT INTO
|
||||
template_version_parameters (
|
||||
template_version_id,
|
||||
name,
|
||||
description,
|
||||
type,
|
||||
mutable,
|
||||
default_value,
|
||||
icon,
|
||||
options,
|
||||
validation_regex,
|
||||
validation_min,
|
||||
validation_max
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11
|
||||
) RETURNING template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max
|
||||
`
|
||||
|
||||
type InsertTemplateVersionParameterParams struct {
|
||||
TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Description string `db:"description" json:"description"`
|
||||
Type string `db:"type" json:"type"`
|
||||
Mutable bool `db:"mutable" json:"mutable"`
|
||||
DefaultValue string `db:"default_value" json:"default_value"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
Options json.RawMessage `db:"options" json:"options"`
|
||||
ValidationRegex string `db:"validation_regex" json:"validation_regex"`
|
||||
ValidationMin int32 `db:"validation_min" json:"validation_min"`
|
||||
ValidationMax int32 `db:"validation_max" json:"validation_max"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg InsertTemplateVersionParameterParams) (TemplateVersionParameter, error) {
|
||||
row := q.db.QueryRowContext(ctx, insertTemplateVersionParameter,
|
||||
arg.TemplateVersionID,
|
||||
arg.Name,
|
||||
arg.Description,
|
||||
arg.Type,
|
||||
arg.Mutable,
|
||||
arg.DefaultValue,
|
||||
arg.Icon,
|
||||
arg.Options,
|
||||
arg.ValidationRegex,
|
||||
arg.ValidationMin,
|
||||
arg.ValidationMax,
|
||||
)
|
||||
var i TemplateVersionParameter
|
||||
err := row.Scan(
|
||||
&i.TemplateVersionID,
|
||||
&i.Name,
|
||||
&i.Description,
|
||||
&i.Type,
|
||||
&i.Mutable,
|
||||
&i.DefaultValue,
|
||||
&i.Icon,
|
||||
&i.Options,
|
||||
&i.ValidationRegex,
|
||||
&i.ValidationMin,
|
||||
&i.ValidationMax,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getPreviousTemplateVersion = `-- name: GetPreviousTemplateVersion :one
|
||||
SELECT
|
||||
id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by
|
||||
@ -5384,6 +5499,59 @@ func (q *sqlQuerier) UpdateWorkspaceAppHealthByID(ctx context.Context, arg Updat
|
||||
return err
|
||||
}
|
||||
|
||||
const getWorkspaceBuildParameters = `-- name: GetWorkspaceBuildParameters :many
|
||||
SELECT
|
||||
workspace_build_id, name, value
|
||||
FROM
|
||||
workspace_build_parameters
|
||||
WHERE
|
||||
workspace_build_id = $1
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceBuildParameters(ctx context.Context, workspaceBuildID uuid.UUID) ([]WorkspaceBuildParameter, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getWorkspaceBuildParameters, workspaceBuildID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []WorkspaceBuildParameter
|
||||
for rows.Next() {
|
||||
var i WorkspaceBuildParameter
|
||||
if err := rows.Scan(&i.WorkspaceBuildID, &i.Name, &i.Value); 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 insertWorkspaceBuildParameters = `-- name: InsertWorkspaceBuildParameters :exec
|
||||
INSERT INTO
|
||||
workspace_build_parameters (workspace_build_id, name, value)
|
||||
SELECT
|
||||
$1 :: uuid AS workspace_build_id,
|
||||
unnest($2 :: text[]) AS name,
|
||||
unnest($3 :: text[]) AS value
|
||||
RETURNING workspace_build_id, name, value
|
||||
`
|
||||
|
||||
type InsertWorkspaceBuildParametersParams struct {
|
||||
WorkspaceBuildID uuid.UUID `db:"workspace_build_id" json:"workspace_build_id"`
|
||||
Name []string `db:"name" json:"name"`
|
||||
Value []string `db:"value" json:"value"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertWorkspaceBuildParameters(ctx context.Context, arg InsertWorkspaceBuildParametersParams) error {
|
||||
_, err := q.db.ExecContext(ctx, insertWorkspaceBuildParameters, arg.WorkspaceBuildID, pq.Array(arg.Name), pq.Array(arg.Value))
|
||||
return err
|
||||
}
|
||||
|
||||
const getLatestWorkspaceBuildByWorkspaceID = `-- name: GetLatestWorkspaceBuildByWorkspaceID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost
|
||||
|
32
coderd/database/queries/templateversionparameters.sql
Normal file
32
coderd/database/queries/templateversionparameters.sql
Normal file
@ -0,0 +1,32 @@
|
||||
-- name: InsertTemplateVersionParameter :one
|
||||
INSERT INTO
|
||||
template_version_parameters (
|
||||
template_version_id,
|
||||
name,
|
||||
description,
|
||||
type,
|
||||
mutable,
|
||||
default_value,
|
||||
icon,
|
||||
options,
|
||||
validation_regex,
|
||||
validation_min,
|
||||
validation_max
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11
|
||||
) RETURNING *;
|
||||
|
||||
-- name: GetTemplateVersionParameters :many
|
||||
SELECT * FROM template_version_parameters WHERE template_version_id = $1;
|
16
coderd/database/queries/workspacebuildparameters.sql
Normal file
16
coderd/database/queries/workspacebuildparameters.sql
Normal file
@ -0,0 +1,16 @@
|
||||
-- name: InsertWorkspaceBuildParameters :exec
|
||||
INSERT INTO
|
||||
workspace_build_parameters (workspace_build_id, name, value)
|
||||
SELECT
|
||||
@workspace_build_id :: uuid AS workspace_build_id,
|
||||
unnest(@name :: text[]) AS name,
|
||||
unnest(@value :: text[]) AS value
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetWorkspaceBuildParameters :many
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
workspace_build_parameters
|
||||
WHERE
|
||||
workspace_build_id = $1;
|
@ -6,26 +6,28 @@ type UniqueConstraint string
|
||||
|
||||
// UniqueConstraint enums.
|
||||
const (
|
||||
UniqueFilesHashCreatedByKey UniqueConstraint = "files_hash_created_by_key" // ALTER TABLE ONLY files ADD CONSTRAINT files_hash_created_by_key UNIQUE (hash, created_by);
|
||||
UniqueGitAuthLinksProviderIDUserIDKey UniqueConstraint = "git_auth_links_provider_id_user_id_key" // ALTER TABLE ONLY git_auth_links ADD CONSTRAINT git_auth_links_provider_id_user_id_key UNIQUE (provider_id, user_id);
|
||||
UniqueGroupMembersUserIDGroupIDKey UniqueConstraint = "group_members_user_id_group_id_key" // ALTER TABLE ONLY group_members ADD CONSTRAINT group_members_user_id_group_id_key UNIQUE (user_id, group_id);
|
||||
UniqueGroupsNameOrganizationIDKey UniqueConstraint = "groups_name_organization_id_key" // ALTER TABLE ONLY groups ADD CONSTRAINT groups_name_organization_id_key UNIQUE (name, organization_id);
|
||||
UniqueLicensesJWTKey UniqueConstraint = "licenses_jwt_key" // ALTER TABLE ONLY licenses ADD CONSTRAINT licenses_jwt_key UNIQUE (jwt);
|
||||
UniqueParameterSchemasJobIDNameKey UniqueConstraint = "parameter_schemas_job_id_name_key" // ALTER TABLE ONLY parameter_schemas ADD CONSTRAINT parameter_schemas_job_id_name_key UNIQUE (job_id, name);
|
||||
UniqueParameterValuesScopeIDNameKey UniqueConstraint = "parameter_values_scope_id_name_key" // ALTER TABLE ONLY parameter_values ADD CONSTRAINT parameter_values_scope_id_name_key UNIQUE (scope_id, name);
|
||||
UniqueProvisionerDaemonsNameKey UniqueConstraint = "provisioner_daemons_name_key" // ALTER TABLE ONLY provisioner_daemons ADD CONSTRAINT provisioner_daemons_name_key UNIQUE (name);
|
||||
UniqueSiteConfigsKeyKey UniqueConstraint = "site_configs_key_key" // ALTER TABLE ONLY site_configs ADD CONSTRAINT site_configs_key_key UNIQUE (key);
|
||||
UniqueTemplateVersionsTemplateIDNameKey UniqueConstraint = "template_versions_template_id_name_key" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_name_key UNIQUE (template_id, name);
|
||||
UniqueWorkspaceAppsAgentIDSlugIndex UniqueConstraint = "workspace_apps_agent_id_slug_idx" // ALTER TABLE ONLY workspace_apps ADD CONSTRAINT workspace_apps_agent_id_slug_idx UNIQUE (agent_id, slug);
|
||||
UniqueWorkspaceBuildsJobIDKey UniqueConstraint = "workspace_builds_job_id_key" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_job_id_key UNIQUE (job_id);
|
||||
UniqueWorkspaceBuildsWorkspaceIDBuildNumberKey UniqueConstraint = "workspace_builds_workspace_id_build_number_key" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_workspace_id_build_number_key UNIQUE (workspace_id, build_number);
|
||||
UniqueWorkspaceResourceMetadataName UniqueConstraint = "workspace_resource_metadata_name" // ALTER TABLE ONLY workspace_resource_metadata ADD CONSTRAINT workspace_resource_metadata_name UNIQUE (workspace_resource_id, key);
|
||||
UniqueIndexOrganizationName UniqueConstraint = "idx_organization_name" // CREATE UNIQUE INDEX idx_organization_name ON organizations USING btree (name);
|
||||
UniqueIndexOrganizationNameLower UniqueConstraint = "idx_organization_name_lower" // CREATE UNIQUE INDEX idx_organization_name_lower ON organizations USING btree (lower(name));
|
||||
UniqueIndexUsersEmail UniqueConstraint = "idx_users_email" // CREATE UNIQUE INDEX idx_users_email ON users USING btree (email) WHERE (deleted = false);
|
||||
UniqueIndexUsersUsername UniqueConstraint = "idx_users_username" // CREATE UNIQUE INDEX idx_users_username ON users USING btree (username) WHERE (deleted = false);
|
||||
UniqueTemplatesOrganizationIDNameIndex UniqueConstraint = "templates_organization_id_name_idx" // CREATE UNIQUE INDEX templates_organization_id_name_idx ON templates USING btree (organization_id, lower((name)::text)) WHERE (deleted = false);
|
||||
UniqueUsersEmailLowerIndex UniqueConstraint = "users_email_lower_idx" // CREATE UNIQUE INDEX users_email_lower_idx ON users USING btree (lower(email)) WHERE (deleted = false);
|
||||
UniqueUsersUsernameLowerIndex UniqueConstraint = "users_username_lower_idx" // CREATE UNIQUE INDEX users_username_lower_idx ON users USING btree (lower(username)) WHERE (deleted = false);
|
||||
UniqueWorkspacesOwnerIDLowerIndex UniqueConstraint = "workspaces_owner_id_lower_idx" // CREATE UNIQUE INDEX workspaces_owner_id_lower_idx ON workspaces USING btree (owner_id, lower((name)::text)) WHERE (deleted = false);
|
||||
UniqueFilesHashCreatedByKey UniqueConstraint = "files_hash_created_by_key" // ALTER TABLE ONLY files ADD CONSTRAINT files_hash_created_by_key UNIQUE (hash, created_by);
|
||||
UniqueGitAuthLinksProviderIDUserIDKey UniqueConstraint = "git_auth_links_provider_id_user_id_key" // ALTER TABLE ONLY git_auth_links ADD CONSTRAINT git_auth_links_provider_id_user_id_key UNIQUE (provider_id, user_id);
|
||||
UniqueGroupMembersUserIDGroupIDKey UniqueConstraint = "group_members_user_id_group_id_key" // ALTER TABLE ONLY group_members ADD CONSTRAINT group_members_user_id_group_id_key UNIQUE (user_id, group_id);
|
||||
UniqueGroupsNameOrganizationIDKey UniqueConstraint = "groups_name_organization_id_key" // ALTER TABLE ONLY groups ADD CONSTRAINT groups_name_organization_id_key UNIQUE (name, organization_id);
|
||||
UniqueLicensesJWTKey UniqueConstraint = "licenses_jwt_key" // ALTER TABLE ONLY licenses ADD CONSTRAINT licenses_jwt_key UNIQUE (jwt);
|
||||
UniqueParameterSchemasJobIDNameKey UniqueConstraint = "parameter_schemas_job_id_name_key" // ALTER TABLE ONLY parameter_schemas ADD CONSTRAINT parameter_schemas_job_id_name_key UNIQUE (job_id, name);
|
||||
UniqueParameterValuesScopeIDNameKey UniqueConstraint = "parameter_values_scope_id_name_key" // ALTER TABLE ONLY parameter_values ADD CONSTRAINT parameter_values_scope_id_name_key UNIQUE (scope_id, name);
|
||||
UniqueProvisionerDaemonsNameKey UniqueConstraint = "provisioner_daemons_name_key" // ALTER TABLE ONLY provisioner_daemons ADD CONSTRAINT provisioner_daemons_name_key UNIQUE (name);
|
||||
UniqueSiteConfigsKeyKey UniqueConstraint = "site_configs_key_key" // ALTER TABLE ONLY site_configs ADD CONSTRAINT site_configs_key_key UNIQUE (key);
|
||||
UniqueTemplateVersionParametersTemplateVersionIDNameKey UniqueConstraint = "template_version_parameters_template_version_id_name_key" // ALTER TABLE ONLY template_version_parameters ADD CONSTRAINT template_version_parameters_template_version_id_name_key UNIQUE (template_version_id, name);
|
||||
UniqueTemplateVersionsTemplateIDNameKey UniqueConstraint = "template_versions_template_id_name_key" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_name_key UNIQUE (template_id, name);
|
||||
UniqueWorkspaceAppsAgentIDSlugIndex UniqueConstraint = "workspace_apps_agent_id_slug_idx" // ALTER TABLE ONLY workspace_apps ADD CONSTRAINT workspace_apps_agent_id_slug_idx UNIQUE (agent_id, slug);
|
||||
UniqueWorkspaceBuildParametersWorkspaceBuildIDNameKey UniqueConstraint = "workspace_build_parameters_workspace_build_id_name_key" // ALTER TABLE ONLY workspace_build_parameters ADD CONSTRAINT workspace_build_parameters_workspace_build_id_name_key UNIQUE (workspace_build_id, name);
|
||||
UniqueWorkspaceBuildsJobIDKey UniqueConstraint = "workspace_builds_job_id_key" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_job_id_key UNIQUE (job_id);
|
||||
UniqueWorkspaceBuildsWorkspaceIDBuildNumberKey UniqueConstraint = "workspace_builds_workspace_id_build_number_key" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_workspace_id_build_number_key UNIQUE (workspace_id, build_number);
|
||||
UniqueWorkspaceResourceMetadataName UniqueConstraint = "workspace_resource_metadata_name" // ALTER TABLE ONLY workspace_resource_metadata ADD CONSTRAINT workspace_resource_metadata_name UNIQUE (workspace_resource_id, key);
|
||||
UniqueIndexOrganizationName UniqueConstraint = "idx_organization_name" // CREATE UNIQUE INDEX idx_organization_name ON organizations USING btree (name);
|
||||
UniqueIndexOrganizationNameLower UniqueConstraint = "idx_organization_name_lower" // CREATE UNIQUE INDEX idx_organization_name_lower ON organizations USING btree (lower(name));
|
||||
UniqueIndexUsersEmail UniqueConstraint = "idx_users_email" // CREATE UNIQUE INDEX idx_users_email ON users USING btree (email) WHERE (deleted = false);
|
||||
UniqueIndexUsersUsername UniqueConstraint = "idx_users_username" // CREATE UNIQUE INDEX idx_users_username ON users USING btree (username) WHERE (deleted = false);
|
||||
UniqueTemplatesOrganizationIDNameIndex UniqueConstraint = "templates_organization_id_name_idx" // CREATE UNIQUE INDEX templates_organization_id_name_idx ON templates USING btree (organization_id, lower((name)::text)) WHERE (deleted = false);
|
||||
UniqueUsersEmailLowerIndex UniqueConstraint = "users_email_lower_idx" // CREATE UNIQUE INDEX users_email_lower_idx ON users USING btree (lower(email)) WHERE (deleted = false);
|
||||
UniqueUsersUsernameLowerIndex UniqueConstraint = "users_username_lower_idx" // CREATE UNIQUE INDEX users_username_lower_idx ON users USING btree (lower(username)) WHERE (deleted = false);
|
||||
UniqueWorkspacesOwnerIDLowerIndex UniqueConstraint = "workspaces_owner_id_lower_idx" // CREATE UNIQUE INDEX workspaces_owner_id_lower_idx ON workspaces USING btree (owner_id, lower((name)::text)) WHERE (deleted = false);
|
||||
)
|
||||
|
@ -181,12 +181,18 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac
|
||||
return nil, failJob(fmt.Sprintf("convert workspace transition: %s", err))
|
||||
}
|
||||
|
||||
workspaceBuildParameters, err := server.Database.GetWorkspaceBuildParameters(ctx, workspaceBuild.ID)
|
||||
if err != nil {
|
||||
return nil, failJob(fmt.Sprintf("get workspace build parameters: %s", err))
|
||||
}
|
||||
|
||||
protoJob.Type = &proto.AcquiredJob_WorkspaceBuild_{
|
||||
WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{
|
||||
WorkspaceBuildId: workspaceBuild.ID.String(),
|
||||
WorkspaceName: workspace.Name,
|
||||
State: workspaceBuild.ProvisionerState,
|
||||
ParameterValues: protoParameters,
|
||||
WorkspaceBuildId: workspaceBuild.ID.String(),
|
||||
WorkspaceName: workspace.Name,
|
||||
State: workspaceBuild.ProvisionerState,
|
||||
ParameterValues: protoParameters,
|
||||
RichParameterValues: convertRichParameterValues(workspaceBuildParameters),
|
||||
Metadata: &sdkproto.Provision_Metadata{
|
||||
CoderUrl: server.AccessURL.String(),
|
||||
WorkspaceTransition: transition,
|
||||
@ -597,6 +603,12 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete
|
||||
|
||||
switch jobType := completed.Type.(type) {
|
||||
case *proto.CompletedJob_TemplateImport_:
|
||||
var input TemplateVersionImportJob
|
||||
err = json.Unmarshal(job.Input, &input)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("template version ID is expected: %w", err)
|
||||
}
|
||||
|
||||
for transition, resources := range map[database.WorkspaceTransition][]*sdkproto.Resource{
|
||||
database.WorkspaceTransitionStart: jobType.TemplateImport.StartResources,
|
||||
database.WorkspaceTransitionStop: jobType.TemplateImport.StopResources,
|
||||
@ -615,6 +627,33 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete
|
||||
}
|
||||
}
|
||||
|
||||
for _, richParameter := range jobType.TemplateImport.RichParameters {
|
||||
server.Logger.Info(ctx, "inserting template import job parameter",
|
||||
slog.F("job_id", job.ID.String()),
|
||||
slog.F("parameter_name", richParameter.Name),
|
||||
)
|
||||
options, err := json.Marshal(richParameter.Options)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("marshal parameter options: %w", err)
|
||||
}
|
||||
_, err = server.Database.InsertTemplateVersionParameter(ctx, database.InsertTemplateVersionParameterParams{
|
||||
TemplateVersionID: input.TemplateVersionID,
|
||||
Name: richParameter.Name,
|
||||
Description: richParameter.Description,
|
||||
Type: richParameter.Type,
|
||||
Mutable: richParameter.Mutable,
|
||||
DefaultValue: richParameter.DefaultValue,
|
||||
Icon: richParameter.Icon,
|
||||
Options: options,
|
||||
ValidationRegex: richParameter.ValidationRegex,
|
||||
ValidationMin: richParameter.ValidationMin,
|
||||
ValidationMax: richParameter.ValidationMax,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("insert parameter: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = server.Database.UpdateProvisionerJobWithCompleteByID(ctx, database.UpdateProvisionerJobWithCompleteByIDParams{
|
||||
ID: jobID,
|
||||
UpdatedAt: database.Now(),
|
||||
@ -1056,6 +1095,17 @@ func convertLogSource(logSource proto.LogSource) (database.LogSource, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func convertRichParameterValues(workspaceBuildParameters []database.WorkspaceBuildParameter) []*sdkproto.RichParameterValue {
|
||||
protoParameters := make([]*sdkproto.RichParameterValue, len(workspaceBuildParameters))
|
||||
for i, buildParameter := range workspaceBuildParameters {
|
||||
protoParameters[i] = &sdkproto.RichParameterValue{
|
||||
Name: buildParameter.Name,
|
||||
Value: buildParameter.Value,
|
||||
}
|
||||
}
|
||||
return protoParameters
|
||||
}
|
||||
|
||||
func convertComputedParameterValues(parameters []parameter.ComputedValue) ([]*sdkproto.ParameterValue, error) {
|
||||
protoParameters := make([]*sdkproto.ParameterValue, len(parameters))
|
||||
for i, computedParameter := range parameters {
|
||||
@ -1113,6 +1163,10 @@ func auditActionFromTransition(transition database.WorkspaceTransition) database
|
||||
}
|
||||
}
|
||||
|
||||
type TemplateVersionImportJob struct {
|
||||
TemplateVersionID uuid.UUID `json:"template_version_id"`
|
||||
}
|
||||
|
||||
// WorkspaceProvisionJob is the payload for the "workspace_provision" job type.
|
||||
type WorkspaceProvisionJob struct {
|
||||
WorkspaceBuildID uuid.UUID `json:"workspace_build_id"`
|
||||
|
@ -580,6 +580,7 @@ func TestCompleteJob(t *testing.T) {
|
||||
job, err := srv.Database.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{
|
||||
ID: uuid.New(),
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
Input: []byte(`{"template_version_id": "` + uuid.NewString() + `"}`),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = srv.Database.AcquireProvisionerJob(ctx, database.AcquireProvisionerJobParams{
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"github.com/coder/coder/coderd/rbac"
|
||||
"github.com/coder/coder/codersdk"
|
||||
"github.com/coder/coder/examples"
|
||||
sdkproto "github.com/coder/coder/provisionersdk/proto"
|
||||
)
|
||||
|
||||
// @Summary Get template version by ID
|
||||
@ -192,6 +193,59 @@ func (api *API) templateVersionSchema(rw http.ResponseWriter, r *http.Request) {
|
||||
httpapi.Write(ctx, rw, http.StatusOK, apiSchemas)
|
||||
}
|
||||
|
||||
// @Summary Get rich parameters by template version
|
||||
// @ID get-rich-parameters-by-template-version
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Templates
|
||||
// @Param templateversion path string true "Template version ID" format(uuid)
|
||||
// @Success 200 {array} parameter.ComputedValue
|
||||
// @Router /templateversions/{templateversion}/rich-parameters [get]
|
||||
func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
templateVersion := httpmw.TemplateVersionParam(r)
|
||||
template := httpmw.TemplateParam(r)
|
||||
if !api.Authorize(r, rbac.ActionRead, templateVersion.RBACObject(template)) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching provisioner job.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if !job.CompletedAt.Valid {
|
||||
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
|
||||
Message: "Job hasn't completed!",
|
||||
})
|
||||
return
|
||||
}
|
||||
dbParameters, err := api.Database.GetTemplateVersionParameters(ctx, templateVersion.ID)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error fetching template version parameters.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
params := make([]codersdk.TemplateVersionParameter, 0)
|
||||
for _, dbParameter := range dbParameters {
|
||||
param, err := convertTemplateVersionParameter(dbParameter)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error converting template version parameter.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
params = append(params, param)
|
||||
}
|
||||
httpapi.Write(ctx, rw, http.StatusOK, params)
|
||||
}
|
||||
|
||||
// @Summary Get parameters by template version
|
||||
// @ID get-parameters-by-template-version
|
||||
// @Security CoderSessionToken
|
||||
@ -1142,6 +1196,14 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
|
||||
}
|
||||
}
|
||||
|
||||
templateVersionID := uuid.New()
|
||||
jobInput, err := json.Marshal(provisionerdserver.TemplateVersionImportJob{
|
||||
TemplateVersionID: templateVersionID,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("marshal job input: %w", err)
|
||||
}
|
||||
|
||||
provisionerJob, err = tx.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{
|
||||
ID: jobID,
|
||||
CreatedAt: database.Now(),
|
||||
@ -1152,7 +1214,7 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
|
||||
StorageMethod: database.ProvisionerStorageMethodFile,
|
||||
FileID: file.ID,
|
||||
Type: database.ProvisionerJobTypeTemplateVersionImport,
|
||||
Input: []byte{'{', '}'},
|
||||
Input: jobInput,
|
||||
Tags: tags,
|
||||
})
|
||||
if err != nil {
|
||||
@ -1172,7 +1234,7 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
|
||||
}
|
||||
|
||||
templateVersion, err = tx.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{
|
||||
ID: uuid.New(),
|
||||
ID: templateVersionID,
|
||||
TemplateID: templateID,
|
||||
OrganizationID: organization.ID,
|
||||
CreatedAt: database.Now(),
|
||||
@ -1307,6 +1369,35 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi
|
||||
}
|
||||
}
|
||||
|
||||
func convertTemplateVersionParameter(param database.TemplateVersionParameter) (codersdk.TemplateVersionParameter, error) {
|
||||
var protoOptions []*sdkproto.RichParameterOption
|
||||
err := json.Unmarshal(param.Options, &protoOptions)
|
||||
if err != nil {
|
||||
return codersdk.TemplateVersionParameter{}, err
|
||||
}
|
||||
options := make([]codersdk.TemplateVersionParameterOption, 0)
|
||||
for _, option := range protoOptions {
|
||||
options = append(options, codersdk.TemplateVersionParameterOption{
|
||||
Name: option.Name,
|
||||
Description: option.Description,
|
||||
Value: option.Value,
|
||||
Icon: option.Icon,
|
||||
})
|
||||
}
|
||||
return codersdk.TemplateVersionParameter{
|
||||
Name: param.Name,
|
||||
Description: param.Description,
|
||||
Type: param.Type,
|
||||
Mutable: param.Mutable,
|
||||
DefaultValue: param.DefaultValue,
|
||||
Icon: param.Icon,
|
||||
Options: options,
|
||||
ValidationRegex: param.ValidationRegex,
|
||||
ValidationMin: param.ValidationMin,
|
||||
ValidationMax: param.ValidationMax,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func watchTemplateChannel(id uuid.UUID) string {
|
||||
return fmt.Sprintf("template:%s", id)
|
||||
}
|
||||
|
@ -632,3 +632,56 @@ func TestWorkspaceBuildStatus(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, codersdk.WorkspaceStatusDeleted, workspace.LatestBuild.Status)
|
||||
}
|
||||
|
||||
func TestWorkspaceBuildWithRichParameters(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
ProvisionPlan: []*proto.Provision_Response{
|
||||
{
|
||||
Type: &proto.Provision_Response_Complete{
|
||||
Complete: &proto.Provision_Complete{
|
||||
Parameters: []*proto.RichParameter{
|
||||
{
|
||||
Name: "first_parameter",
|
||||
Description: "This is first parameter",
|
||||
},
|
||||
{
|
||||
Name: "second_parameter",
|
||||
Description: "This is second parameter",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
})
|
||||
coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
|
||||
richParameters, err := client.TemplateVersionRichParameters(ctx, version.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, richParameters, 2)
|
||||
require.Equal(t, richParameters[0].Name, "first_parameter")
|
||||
require.Equal(t, richParameters[1].Name, "second_parameter")
|
||||
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
|
||||
cwr.RichParameterValues = []codersdk.WorkspaceBuildParameter{
|
||||
{
|
||||
Name: "first_parameter",
|
||||
Value: "1",
|
||||
},
|
||||
{
|
||||
Name: "second_parameter",
|
||||
Value: "2",
|
||||
},
|
||||
}
|
||||
})
|
||||
_, err = client.WorkspaceBuild(ctx, workspace.LatestBuild.ID)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user