@@ -29,57 +29,86 @@ import (
29
29
"github.com/coder/websocket"
30
30
)
31
31
32
+ // @Summary Evaluate dynamic parameters for template version
33
+ // @ID evaluate-dynamic-parameters-by-template-version
34
+ // @Security CoderSessionToken
35
+ // @Tags Templates
36
+ // @Param templateversion path string true "Template version ID" format(uuid)
37
+ // @Accept json
38
+ // @Produce json
39
+ // @Router /templateversions/{templateversion}/dynamic-parameters/evaluate [post]
40
+ func (api * API )templateVersionDynamicParametersEvaluate (rw http.ResponseWriter ,r * http.Request ) {
41
+ ctx := r .Context ()
42
+ var req codersdk.DynamicParametersRequest
43
+ if ! httpapi .Read (ctx ,rw ,r ,& req ) {
44
+ return
45
+ }
46
+
47
+ api .templateVersionDynamicParameters (false ,req )(rw ,r )
48
+ }
49
+
32
50
// @Summary Open dynamic parameters WebSocket by template version
33
51
// @ID open-dynamic-parameters-websocket-by-template-version
34
52
// @Security CoderSessionToken
35
53
// @Tags Templates
36
- // @Param user path string true "Template version ID" format(uuid)
37
54
// @Param templateversion path string true "Template version ID" format(uuid)
38
55
// @Success 101
39
56
// @Router /templateversions/{templateversion}/dynamic-parameters [get]
40
- func (api * API )templateVersionDynamicParameters (rw http.ResponseWriter ,r * http.Request ) {
41
- ctx := r .Context ()
42
- templateVersion := httpmw .TemplateVersionParam (r )
57
+ func (api * API )templateVersionDynamicParametersWebsocket (rw http.ResponseWriter ,r * http.Request ) {
58
+ apikey := httpmw .APIKey (r )
59
+
60
+ api .templateVersionDynamicParameters (true , codersdk.DynamicParametersRequest {
61
+ ID :- 1 ,
62
+ Inputs :map [string ]string {},
63
+ OwnerID :apikey .UserID ,
64
+ })(rw ,r )
65
+ }
43
66
44
- // Check that the job has completed successfully
45
- job ,err := api .Database .GetProvisionerJobByID (ctx ,templateVersion .JobID )
46
- if httpapi .Is404Error (err ) {
47
- httpapi .ResourceNotFound (rw )
48
- return
49
- }
50
- if err != nil {
51
- httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
52
- Message :"Internal error fetching provisioner job." ,
53
- Detail :err .Error (),
54
- })
55
- return
56
- }
57
- if ! job .CompletedAt .Valid {
58
- httpapi .Write (ctx ,rw ,http .StatusTooEarly , codersdk.Response {
59
- Message :"Template version job has not finished" ,
60
- })
61
- return
62
- }
67
+ func (api * API )templateVersionDynamicParameters (listen bool ,initial codersdk.DynamicParametersRequest )func (rw http.ResponseWriter ,r * http.Request ) {
68
+ return func (rw http.ResponseWriter ,r * http.Request ) {
69
+ ctx := r .Context ()
70
+ templateVersion := httpmw .TemplateVersionParam (r )
63
71
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
- })
70
- return
71
- }
72
+ // Check that the job has completed successfully
73
+ job ,err := api .Database .GetProvisionerJobByID (ctx ,templateVersion .JobID )
74
+ if httpapi .Is404Error (err ) {
75
+ httpapi .ResourceNotFound (rw )
76
+ return
77
+ }
78
+ if err != nil {
79
+ httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
80
+ Message :"Internal error fetching provisioner job." ,
81
+ Detail :err .Error (),
82
+ })
83
+ return
84
+ }
85
+ if ! job .CompletedAt .Valid {
86
+ httpapi .Write (ctx ,rw ,http .StatusTooEarly , codersdk.Response {
87
+ Message :"Template version job has not finished" ,
88
+ })
89
+ return
90
+ }
72
91
73
- if wsbuilder .ProvisionerVersionSupportsDynamicParameters (tf .ProvisionerdVersion ) {
74
- api .handleDynamicParameters (rw ,r ,tf ,templateVersion )
75
- }else {
76
- api .handleStaticParameters (rw ,r ,templateVersion .ID )
92
+ tf ,err := api .Database .GetTemplateVersionTerraformValues (ctx ,templateVersion .ID )
93
+ if err != nil && ! xerrors .Is (err ,sql .ErrNoRows ) {
94
+ httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
95
+ Message :"Failed to retrieve Terraform values for template version" ,
96
+ Detail :err .Error (),
97
+ })
98
+ return
99
+ }
100
+
101
+ if wsbuilder .ProvisionerVersionSupportsDynamicParameters (tf .ProvisionerdVersion ) {
102
+ api .handleDynamicParameters (listen ,rw ,r ,tf ,templateVersion ,initial )
103
+ }else {
104
+ api .handleStaticParameters (listen ,rw ,r ,templateVersion .ID ,initial )
105
+ }
77
106
}
78
107
}
79
108
80
109
type previewFunction func (ctx context.Context ,ownerID uuid.UUID ,values map [string ]string ) (* preview.Output , hcl.Diagnostics )
81
110
82
- func (api * API )handleDynamicParameters (rw http.ResponseWriter ,r * http.Request ,tf database.TemplateVersionTerraformValue ,templateVersion database.TemplateVersion ) {
111
+ func (api * API )handleDynamicParameters (listen bool , rw http.ResponseWriter ,r * http.Request ,tf database.TemplateVersionTerraformValue ,templateVersion database.TemplateVersion , initial codersdk. DynamicParametersRequest ) {
83
112
var (
84
113
ctx = r .Context ()
85
114
apikey = httpmw .APIKey (r )
@@ -159,7 +188,7 @@ func (api *API) handleDynamicParameters(rw http.ResponseWriter, r *http.Request,
159
188
},
160
189
}
161
190
162
- api . handleParameterWebsocket ( rw , r , apikey . UserID , func (ctx context.Context ,ownerID uuid.UUID ,values map [string ]string ) (* preview.Output , hcl.Diagnostics ) {
191
+ dynamicRender := func (ctx context.Context ,ownerID uuid.UUID ,values map [string ]string ) (* preview.Output , hcl.Diagnostics ) {
163
192
if ownerID == uuid .Nil {
164
193
// Default to the authenticated user
165
194
// Nice for testing
@@ -186,10 +215,15 @@ func (api *API) handleDynamicParameters(rw http.ResponseWriter, r *http.Request,
186
215
}
187
216
188
217
return preview .Preview (ctx ,input ,templateFS )
189
- })
218
+ }
219
+ if listen {
220
+ api .handleParameterWebsocket (rw ,r ,initial ,dynamicRender )
221
+ }else {
222
+ api .handleParameterEvaluate (rw ,r ,initial ,dynamicRender )
223
+ }
190
224
}
191
225
192
- func (api * API )handleStaticParameters (rw http.ResponseWriter ,r * http.Request ,version uuid.UUID ) {
226
+ func (api * API )handleStaticParameters (listen bool , rw http.ResponseWriter ,r * http.Request ,version uuid.UUID , initial codersdk. DynamicParametersRequest ) {
193
227
ctx := r .Context ()
194
228
dbTemplateVersionParameters ,err := api .Database .GetTemplateVersionParameters (ctx ,version )
195
229
if err != nil {
@@ -275,7 +309,7 @@ func (api *API) handleStaticParameters(rw http.ResponseWriter, r *http.Request,
275
309
params = append (params ,param )
276
310
}
277
311
278
- api . handleParameterWebsocket ( rw , r , uuid . Nil , func (_ context.Context ,_ uuid.UUID ,values map [string ]string ) (* preview.Output , hcl.Diagnostics ) {
312
+ staticRender := func (_ context.Context ,_ uuid.UUID ,values map [string ]string ) (* preview.Output , hcl.Diagnostics ) {
279
313
for i := range params {
280
314
param := & params [i ]
281
315
paramValue ,ok := values [param .Name ]
@@ -297,10 +331,31 @@ func (api *API) handleStaticParameters(rw http.ResponseWriter, r *http.Request,
297
331
Detail :"To restore full functionality, please re-import the terraform as a new template version." ,
298
332
},
299
333
}
300
- })
334
+ }
335
+ if listen {
336
+ api .handleParameterWebsocket (rw ,r ,initial ,staticRender )
337
+ }else {
338
+ api .handleParameterEvaluate (rw ,r ,initial ,staticRender )
339
+ }
340
+ }
341
+
342
+ func (api * API )handleParameterEvaluate (rw http.ResponseWriter ,r * http.Request ,initial codersdk.DynamicParametersRequest ,render previewFunction ) {
343
+ ctx := r .Context ()
344
+
345
+ // Send an initial form state, computed without any user input.
346
+ result ,diagnostics := render (ctx ,initial .OwnerID ,initial .Inputs )
347
+ response := codersdk.DynamicParametersResponse {
348
+ ID :- 1 ,// Always start with -1.
349
+ Diagnostics :db2sdk .HCLDiagnostics (diagnostics ),
350
+ }
351
+ if result != nil {
352
+ response .Parameters = db2sdk .List (result .Parameters ,db2sdk .PreviewParameter )
353
+ }
354
+
355
+ httpapi .Write (ctx ,rw ,http .StatusOK ,response )
301
356
}
302
357
303
- func (api * API )handleParameterWebsocket (rw http.ResponseWriter ,r * http.Request ,ownerID uuid. UUID ,render previewFunction ) {
358
+ func (api * API )handleParameterWebsocket (rw http.ResponseWriter ,r * http.Request ,initial codersdk. DynamicParametersRequest ,render previewFunction ) {
304
359
ctx ,cancel := context .WithTimeout (r .Context (),30 * time .Minute )
305
360
defer cancel ()
306
361
@@ -320,7 +375,7 @@ func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request
320
375
)
321
376
322
377
// Send an initial form state, computed without any user input.
323
- result ,diagnostics := render (ctx ,ownerID , map [ string ] string {} )
378
+ result ,diagnostics := render (ctx ,initial . OwnerID , initial . Inputs )
324
379
response := codersdk.DynamicParametersResponse {
325
380
ID :- 1 ,// Always start with -1.
326
381
Diagnostics :db2sdk .HCLDiagnostics (diagnostics ),