Skip to content

Commit 2f5f251

Browse files
committed
wip
1 parent 55d2af4 commit 2f5f251

File tree

5 files changed

+225
-89
lines changed

5 files changed

+225
-89
lines changed

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,8 +1214,8 @@ func (s *MethodTestSuite) TestTemplate() {
12141214
JobID: job.ID,
12151215
TemplateID: uuid.NullUUID{UUID: t.ID, Valid: true},
12161216
})
1217-
dbgen.TemplateVersionTerraformValues(s.T(), db, database.InsertTemplateVersionTerraformValuesByJobIDParams{
1218-
JobID: job.ID,
1217+
dbgen.TemplateVersionTerraformValues(s.T(), db, database.TemplateVersionTerraformValue{
1218+
TemplateVersionID: tv.ID,
12191219
})
12201220
check.Args(tv.ID).Asserts(t, policy.ActionRead)
12211221
}))

coderd/database/dbgen/dbgen.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -997,11 +997,19 @@ func TemplateVersionParameter(t testing.TB, db database.Store, orig database.Tem
997997
return version
998998
}
999999

1000-
func TemplateVersionTerraformValues(t testing.TB, db database.Store, orig database.InsertTemplateVersionTerraformValuesByJobIDParams) {
1000+
func TemplateVersionTerraformValues(t testing.TB, db database.Store, orig database.TemplateVersionTerraformValue) database.TemplateVersionTerraformValue {
10011001
t.Helper()
10021002

1003+
jobID := uuid.New()
1004+
if orig.TemplateVersionID != uuid.Nil {
1005+
v, err := db.GetTemplateVersionByID(genCtx, orig.TemplateVersionID)
1006+
if err == nil {
1007+
jobID = v.JobID
1008+
}
1009+
}
1010+
10031011
params := database.InsertTemplateVersionTerraformValuesByJobIDParams{
1004-
JobID: takeFirst(orig.JobID, uuid.New()),
1012+
JobID: jobID,
10051013
CachedPlan: takeFirstSlice(orig.CachedPlan, []byte("{}")),
10061014
CachedModuleFiles: orig.CachedModuleFiles,
10071015
UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()),
@@ -1010,6 +1018,11 @@ func TemplateVersionTerraformValues(t testing.TB, db database.Store, orig databa
10101018

10111019
err := db.InsertTemplateVersionTerraformValuesByJobID(genCtx, params)
10121020
require.NoError(t, err, "insert template version parameter")
1021+
1022+
v, err := db.GetTemplateVersionTerraformValues(genCtx, orig.TemplateVersionID)
1023+
require.NoError(t, err, "get template version values")
1024+
1025+
return v
10131026
}
10141027

10151028
func WorkspaceAgentStat(t testing.TB, db database.Store, orig database.WorkspaceAgentStat) database.WorkspaceAgentStat {

coderd/parameters.go

Lines changed: 112 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"database/sql"
66
"encoding/json"
7-
"io/fs"
87
"net/http"
98
"time"
109

@@ -19,8 +18,10 @@ import (
1918
"github.com/coder/coder/v2/coderd/files"
2019
"github.com/coder/coder/v2/coderd/httpapi"
2120
"github.com/coder/coder/v2/coderd/httpmw"
21+
"github.com/coder/coder/v2/coderd/util/ptr"
2222
"github.com/coder/coder/v2/codersdk"
2323
"github.com/coder/coder/v2/codersdk/wsjson"
24+
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
2425
"github.com/coder/preview"
2526
previewtypes "github.com/coder/preview/types"
2627
"github.com/coder/websocket"
@@ -60,11 +61,38 @@ func (api *API) templateVersionDynamicParameters(rw http.ResponseWriter, r *http
6061
return
6162
}
6263

63-
render, closer, success := prepareDynamicPreview(ctx, rw, api.Database, api.FileCache, templateVersion, user)
64-
if !success {
64+
tf, err := api.Database.GetTemplateVersionTerraformValues(ctx, templateVersion.ID)
65+
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
66+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
67+
Message: "Failed to retrieve Terraform values for template version",
68+
Detail: err.Error(),
69+
})
6570
return
6671
}
67-
defer closer()
72+
73+
staticDiagnostics := parameterProvisionerVersionDiagnostic(tf)
74+
75+
var render previewFunction
76+
major, minor, err := apiversion.Parse(tf.ProvisionerdVersion)
77+
if err != nil || major < 1 || (major == 1 && minor < 5) {
78+
staticRender, err := prepareStaticPreview(ctx, api.Database, templateVersion.ID)
79+
if err != nil {
80+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
81+
Message: "Failed to setup static rendering",
82+
Detail: err.Error(),
83+
})
84+
return
85+
}
86+
render = staticRender
87+
} else {
88+
// If the major version is 1.5+, we can use the dynamic preview
89+
dynamicRender, closer, success := prepareDynamicPreview(ctx, rw, api.Database, api.FileCache, tf, templateVersion, user)
90+
if !success {
91+
return
92+
}
93+
defer closer()
94+
render = dynamicRender
95+
}
6896

6997
conn, err := websocket.Accept(rw, r, nil)
7098
if err != nil {
@@ -128,7 +156,7 @@ func (api *API) templateVersionDynamicParameters(rw http.ResponseWriter, r *http
128156

129157
type previewFunction func(ctx context.Context, values map[string]string) (*preview.Output, hcl.Diagnostics)
130158

131-
func prepareDynamicPreview(ctx context.Context, rw http.ResponseWriter, db database.Store, fc *files.Cache, templateVersion database.TemplateVersion, user database.User) (render previewFunction, closer func(), success bool) {
159+
func prepareDynamicPreview(ctx context.Context, rw http.ResponseWriter, db database.Store, fc *files.Cache, tf database.TemplateVersionTerraformValue, templateVersion database.TemplateVersion, user database.User) (render previewFunction, closer func(), success bool) {
132160
openFiles := make([]uuid.UUID, 0)
133161
closeFiles := func() {
134162
for _, it := range openFiles {
@@ -167,36 +195,20 @@ func prepareDynamicPreview(ctx context.Context, rw http.ResponseWriter, db datab
167195
// for populating values from data blocks, but isn't strictly required. If
168196
// we don't have a cached plan available, we just use an empty one instead.
169197
plan := json.RawMessage("{}")
170-
tf, err := db.GetTemplateVersionTerraformValues(ctx, templateVersion.ID)
171-
if err == nil {
172-
plan = tf.CachedPlan
173-
174-
if tf.CachedModuleFiles.Valid {
175-
moduleFilesFS, err := fc.Acquire(fileCtx, tf.CachedModuleFiles.UUID)
176-
if err != nil {
177-
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
178-
Message: "Internal error fetching Terraform modules.",
179-
Detail: err.Error(),
180-
})
181-
return nil, nil, false
182-
}
183-
openFiles = append(openFiles, tf.CachedModuleFiles.UUID)
198+
plan = tf.CachedPlan
184199

185-
templateFS, err = files.NewOverlayFS(templateFS, []files.Overlay{{Path: ".terraform/modules", FS: moduleFilesFS}})
186-
if err != nil {
187-
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
188-
Message: "Internal error creating overlay filesystem.",
189-
Detail: err.Error(),
190-
})
191-
return nil, nil, false
192-
}
200+
if tf.CachedModuleFiles.Valid {
201+
moduleFilesFS, err := fc.Acquire(fileCtx, tf.CachedModuleFiles.UUID)
202+
if err != nil {
203+
httpapi.Write(ctx, rw, http.StatusNotFound, codersdk.Response{
204+
Message: "Internal error fetching Terraform modules.",
205+
Detail: err.Error(),
206+
})
207+
return nil, nil, false
193208
}
194-
} else if !xerrors.Is(err, sql.ErrNoRows) {
195-
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
196-
Message: "Failed to retrieve Terraform values for template version",
197-
Detail: err.Error(),
198-
})
199-
return nil, nil, false
209+
openFiles = append(openFiles, tf.CachedModuleFiles.UUID)
210+
211+
templateFS = files.NewOverlayFS(templateFS, []files.Overlay{{Path: ".terraform/modules", FS: moduleFilesFS}})
200212
}
201213

202214
owner, err := getWorkspaceOwnerData(ctx, db, user, templateVersion.OrganizationID)
@@ -219,15 +231,15 @@ func prepareDynamicPreview(ctx context.Context, rw http.ResponseWriter, db datab
219231
}, closeFiles, true
220232
}
221233

222-
func staticPreview(ctx context.Context, db database.Store, version uuid.UUID) func(ctx context.Context, input preview.Input, fs fs.FS) preview.Output {
234+
func prepareStaticPreview(ctx context.Context, db database.Store, version uuid.UUID) (previewFunction, error) {
223235
dbTemplateVersionParameters, err := db.GetTemplateVersionParameters(ctx, version)
224236
if err != nil {
225-
return nil
237+
return nil, xerrors.Errorf("error fetching template version parameters: %w", err)
226238
}
227239

228240
params := make([]previewtypes.Parameter, 0, len(dbTemplateVersionParameters))
229241
for _, it := range dbTemplateVersionParameters {
230-
params = append(params, previewtypes.Parameter{
242+
param := previewtypes.Parameter{
231243
ParameterData: previewtypes.ParameterData{
232244
Name: it.Name,
233245
DisplayName: it.DisplayName,
@@ -240,22 +252,77 @@ func staticPreview(ctx context.Context, db database.Store, version uuid.UUID) fu
240252
Icon: it.Icon,
241253
Options: nil,
242254
Validations: nil,
243-
Required: false,
244-
Order: 0,
245-
Ephemeral: false,
255+
Required: it.Required,
256+
Order: int64(it.DisplayOrder),
257+
Ephemeral: it.Ephemeral,
246258
Source: nil,
247259
},
248-
Value: previewtypes.NullString(),
260+
// Always use the default, since we used to assume the empty string
261+
Value: previewtypes.StringLiteral(it.DefaultValue),
249262
Diagnostics: nil,
250-
})
251-
}
263+
}
252264

253-
return func(_ context.Context, in preview.Input, _ fs.FS) preview.Output {
265+
if it.ValidationError != "" || it.ValidationRegex != "" || it.ValidationMonotonic != "" {
266+
var reg *string
267+
if it.ValidationRegex != "" {
268+
reg = ptr.Ref(it.ValidationRegex)
269+
}
270+
271+
var vMin *int64
272+
if it.ValidationMin.Valid {
273+
vMin = ptr.Ref(int64(it.ValidationMin.Int32))
274+
}
254275

255-
return preview.Output{
256-
Parameters: nil,
276+
var vMax *int64
277+
if it.ValidationMax.Valid {
278+
vMin = ptr.Ref(int64(it.ValidationMax.Int32))
279+
}
280+
281+
var monotonic *string
282+
if it.ValidationMonotonic != "" {
283+
monotonic = ptr.Ref(it.ValidationMonotonic)
284+
}
285+
286+
param.Validations = append(param.Validations, &previewtypes.ParameterValidation{
287+
Error: it.ValidationError,
288+
Regex: reg,
289+
Min: vMin,
290+
Max: vMax,
291+
Monotonic: monotonic,
292+
})
293+
}
294+
295+
var protoOptions []*sdkproto.RichParameterOption
296+
_ = json.Unmarshal(it.Options, &protoOptions) // Not going to make this fatal
297+
for _, opt := range protoOptions {
298+
param.Options = append(param.Options, &previewtypes.ParameterOption{
299+
Name: opt.Name,
300+
Description: opt.Description,
301+
Value: previewtypes.StringLiteral(opt.Value),
302+
Icon: opt.Icon,
303+
})
257304
}
305+
306+
param.Diagnostics = previewtypes.Diagnostics(param.Valid(param.Value))
307+
params = append(params, param)
258308
}
309+
310+
return func(ctx context.Context, values map[string]string) (*preview.Output, hcl.Diagnostics) {
311+
for i := range params {
312+
param := &params[i]
313+
paramValue, ok := values[param.Name]
314+
if ok {
315+
param.Value = previewtypes.StringLiteral(paramValue)
316+
} else {
317+
paramValue = param.DefaultValue.AsString()
318+
}
319+
param.Diagnostics = previewtypes.Diagnostics(param.Valid(param.Value))
320+
}
321+
322+
return &preview.Output{
323+
Parameters: params,
324+
}, nil
325+
}, nil
259326
}
260327

261328
func getWorkspaceOwnerData(

coderd/parameters_internal_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ func Test_prepareDynamicPreview(t *testing.T) {
2424
t.Parallel()
2525

2626
t.Run("Success", func(t *testing.T) {
27-
db, fc, ver, user := setupPrepareDynamicPreview(t, ``, ptr.Ref("{}"))
27+
db, fc, tf, ver, user := setupPrepareDynamicPreview(t, ``, ptr.Ref("{}"))
2828
rec := httptest.NewRecorder()
29-
_, closer, success := prepareDynamicPreview(context.Background(), rec, db, fc, ver, user)
29+
_, closer, success := prepareDynamicPreview(context.Background(), rec, db, fc, tf, ver, user)
3030
require.True(t, success)
3131

3232
require.Equal(t, fc.Count(), 3)
@@ -36,7 +36,7 @@ func Test_prepareDynamicPreview(t *testing.T) {
3636
})
3737
}
3838

39-
func setupPrepareDynamicPreview(t *testing.T, tf string, modules *string) (database.Store, *files.Cache, database.TemplateVersion, database.User) {
39+
func setupPrepareDynamicPreview(t *testing.T, tf string, modules *string) (database.Store, *files.Cache, database.TemplateVersionTerraformValue, database.TemplateVersion, database.User) {
4040
db := dbmem.New()
4141

4242
versionFile := dbgen.File(t, db, database.File{})
@@ -58,8 +58,8 @@ func setupPrepareDynamicPreview(t *testing.T, tf string, modules *string) (datab
5858
}
5959
}
6060

61-
dbgen.TemplateVersionTerraformValues(t, db, database.InsertTemplateVersionTerraformValuesByJobIDParams{
62-
JobID: job.ID,
61+
tfVals := dbgen.TemplateVersionTerraformValues(t, db, database.TemplateVersionTerraformValue{
62+
TemplateVersionID: ver.ID,
6363
UpdatedAt: time.Time{},
6464
CachedPlan: nil,
6565
CachedModuleFiles: modulesFile,
@@ -91,7 +91,7 @@ func setupPrepareDynamicPreview(t *testing.T, tf string, modules *string) (datab
9191
return nil, sql.ErrNoRows
9292
})
9393

94-
return db, fc, ver, user
94+
return db, fc, tfVals, ver, user
9595
}
9696

9797
func Test_parameterProvisionerVersionDiagnostic(t *testing.T) {

0 commit comments

Comments
 (0)