@@ -178,6 +178,198 @@ func New() *schema.Provider {
178
178
},
179
179
},
180
180
},
181
+ "coder_parameter" : {
182
+ Description : "Use this data source to configure editable options for workspaces." ,
183
+ ReadContext : func (ctx context.Context , rd * schema.ResourceData , i interface {}) diag.Diagnostics {
184
+ rd .SetId (uuid .NewString ())
185
+
186
+ name := rd .Get ("name" ).(string )
187
+ typ := rd .Get ("type" ).(string )
188
+ var value string
189
+ rawDefaultValue , ok := rd .GetOk ("default" )
190
+ if ok {
191
+ defaultValue := rawDefaultValue .(string )
192
+ err := valueIsType (typ , defaultValue )
193
+ if err != nil {
194
+ return err
195
+ }
196
+ value = defaultValue
197
+ }
198
+ envValue , ok := os .LookupEnv (fmt .Sprintf ("CODER_PARAMETER_%s" , name ))
199
+ if ok {
200
+ value = envValue
201
+ }
202
+ rd .Set ("value" , value )
203
+
204
+ rawOptions , exists := rd .GetOk ("option" )
205
+ if exists {
206
+ rawArrayOptions , valid := rawOptions .([]interface {})
207
+ if ! valid {
208
+ return diag .Errorf ("options is of wrong type %T" , rawArrayOptions )
209
+ }
210
+ optionDisplayNames := map [string ]interface {}{}
211
+ optionValues := map [string ]interface {}{}
212
+ for _ , rawOption := range rawArrayOptions {
213
+ option , valid := rawOption .(map [string ]interface {})
214
+ if ! valid {
215
+ return diag .Errorf ("option is of wrong type %T" , rawOption )
216
+ }
217
+ rawName , ok := option ["name" ]
218
+ if ! ok {
219
+ return diag .Errorf ("no name for %+v" , option )
220
+ }
221
+ displayName , ok := rawName .(string )
222
+ if ! ok {
223
+ return diag .Errorf ("display name is of wrong type %T" , displayName )
224
+ }
225
+ _ , exists := optionDisplayNames [displayName ]
226
+ if exists {
227
+ return diag .Errorf ("multiple options cannot have the same display name %q" , displayName )
228
+ }
229
+
230
+ rawValue , ok := option ["value" ]
231
+ if ! ok {
232
+ return diag .Errorf ("no value for %+v\n " , option )
233
+ }
234
+ value , ok := rawValue .(string )
235
+ if ! ok {
236
+ return diag .Errorf ("" )
237
+ }
238
+ _ , exists = optionValues [value ]
239
+ if exists {
240
+ return diag .Errorf ("multiple options cannot have the same value %q" , value )
241
+ }
242
+ err := valueIsType (typ , value )
243
+ if err != nil {
244
+ return err
245
+ }
246
+
247
+ optionValues [value ] = nil
248
+ optionDisplayNames [displayName ] = nil
249
+ }
250
+ }
251
+
252
+ return nil
253
+ },
254
+ Schema : map [string ]* schema.Schema {
255
+ "value" : {
256
+ Type : schema .TypeString ,
257
+ Computed : true ,
258
+ Description : "The output value of a parameter." ,
259
+ },
260
+ "name" : {
261
+ Type : schema .TypeString ,
262
+ Required : true ,
263
+ Description : "The name of the parameter as it appears in the interface. If this is changed, the parameter will need to be re-updated by developers." ,
264
+ },
265
+ "description" : {
266
+ Type : schema .TypeString ,
267
+ Optional : true ,
268
+ Description : "Explain what the parameter does." ,
269
+ },
270
+ "type" : {
271
+ Type : schema .TypeString ,
272
+ Default : "string" ,
273
+ Optional : true ,
274
+ ValidateFunc : validation .StringInSlice ([]string {"number" , "string" , "bool" }, false ),
275
+ },
276
+ "immutable" : {
277
+ Type : schema .TypeBool ,
278
+ Optional : true ,
279
+ Description : "Whether the value can be changed after it's set initially." ,
280
+ },
281
+ "default" : {
282
+ Type : schema .TypeString ,
283
+ Optional : true ,
284
+ Description : "A default value for the parameter." ,
285
+ ExactlyOneOf : []string {"option" },
286
+ },
287
+ "icon" : {
288
+ Type : schema .TypeString ,
289
+ Description : "A URL to an icon that will display in the dashboard. View built-in " +
290
+ "icons here: https://github.com/coder/coder/tree/main/site/static/icon. Use a " +
291
+ "built-in icon with `data.coder_workspace.me.access_url + \" /icon/<path>\" `." ,
292
+ ForceNew : true ,
293
+ Optional : true ,
294
+ ValidateFunc : func (i interface {}, s string ) ([]string , []error ) {
295
+ _ , err := url .Parse (s )
296
+ if err != nil {
297
+ return nil , []error {err }
298
+ }
299
+ return nil , nil
300
+ },
301
+ },
302
+ "option" : {
303
+ Type : schema .TypeList ,
304
+ Description : "Each \" option\" block defines a single displayable value for a user to select." ,
305
+ ForceNew : true ,
306
+ Optional : true ,
307
+ MaxItems : 64 ,
308
+ Elem : & schema.Resource {
309
+ Schema : map [string ]* schema.Schema {
310
+ "name" : {
311
+ Type : schema .TypeString ,
312
+ Description : "The display name of this value in the UI." ,
313
+ ForceNew : true ,
314
+ Required : true ,
315
+ },
316
+ "description" : {
317
+ Type : schema .TypeString ,
318
+ Description : "Add a description to select this item." ,
319
+ ForceNew : true ,
320
+ Optional : true ,
321
+ },
322
+ "value" : {
323
+ Type : schema .TypeString ,
324
+ Description : "The value of this option." ,
325
+ ForceNew : true ,
326
+ Required : true ,
327
+ },
328
+ "icon" : {
329
+ Type : schema .TypeString ,
330
+ Description : "A URL to an icon that will display in the dashboard. View built-in " +
331
+ "icons here: https://github.com/coder/coder/tree/main/site/static/icon. Use a " +
332
+ "built-in icon with `data.coder_workspace.me.access_url + \" /icon/<path>\" `." ,
333
+ ForceNew : true ,
334
+ Optional : true ,
335
+ ValidateFunc : func (i interface {}, s string ) ([]string , []error ) {
336
+ _ , err := url .Parse (s )
337
+ if err != nil {
338
+ return nil , []error {err }
339
+ }
340
+ return nil , nil
341
+ },
342
+ },
343
+ },
344
+ },
345
+ },
346
+ "validation" : {
347
+ Type : schema .TypeSet ,
348
+ MaxItems : 1 ,
349
+ Optional : true ,
350
+ Elem : & schema.Resource {
351
+ Schema : map [string ]* schema.Schema {
352
+ "min" : {
353
+ Type : schema .TypeInt ,
354
+ Optional : true ,
355
+ Default : 0 ,
356
+ Description : "The minimum for a number to be." ,
357
+ },
358
+ "max" : {
359
+ Type : schema .TypeInt ,
360
+ Optional : true ,
361
+ Description : "The maximum for a number to be." ,
362
+ },
363
+ "regex" : {
364
+ Type : schema .TypeString ,
365
+ ExactlyOneOf : []string {"min" , "max" },
366
+ Optional : true ,
367
+ },
368
+ },
369
+ },
370
+ },
371
+ },
372
+ },
181
373
"coder_provisioner" : {
182
374
Description : "Use this data source to get information about the Coder provisioner." ,
183
375
ReadContext : func (c context.Context , rd * schema.ResourceData , i interface {}) diag.Diagnostics {
@@ -339,8 +531,8 @@ func New() *schema.Provider {
339
531
"icon" : {
340
532
Type : schema .TypeString ,
341
533
Description : "A URL to an icon that will display in the dashboard. View built-in " +
342
- "icons here: https://github.com/coder/coder/tree/main/site/static/icons . Use a " +
343
- "built-in icon with `data.coder_workspace.me.access_url + \" /icons /<path>\" `." ,
534
+ "icons here: https://github.com/coder/coder/tree/main/site/static/icon . Use a " +
535
+ "built-in icon with `data.coder_workspace.me.access_url + \" /icon /<path>\" `." ,
344
536
ForceNew : true ,
345
537
Optional : true ,
346
538
ValidateFunc : func (i interface {}, s string ) ([]string , []error ) {
@@ -445,7 +637,7 @@ func New() *schema.Provider {
445
637
Type : schema .TypeString ,
446
638
Description : "A URL to an icon that will display in the dashboard. View built-in " +
447
639
"icons here: https://github.com/coder/coder/tree/main/site/static/icon. Use a " +
448
- "built-in icon with `data.coder_workspace.me.access_url + \" /icons /<path>\" `." ,
640
+ "built-in icon with `data.coder_workspace.me.access_url + \" /icon /<path>\" `." ,
449
641
ForceNew : true ,
450
642
Optional : true ,
451
643
ValidateFunc : func (i interface {}, s string ) ([]string , []error ) {
@@ -499,6 +691,26 @@ func New() *schema.Provider {
499
691
}
500
692
}
501
693
694
+ func valueIsType (typ , value string ) diag.Diagnostics {
695
+ switch typ {
696
+ case "number" :
697
+ _ , err := strconv .ParseFloat (value , 64 )
698
+ if err != nil {
699
+ return diag .Errorf ("%q is not a number" , value )
700
+ }
701
+ case "bool" :
702
+ _ , err := strconv .ParseBool (value )
703
+ if err != nil {
704
+ return diag .Errorf ("%q is not a bool" , value )
705
+ }
706
+ case "string" :
707
+ // Anything is a string!
708
+ default :
709
+ return diag .Errorf ("invalid type %q" , typ )
710
+ }
711
+ return nil
712
+ }
713
+
502
714
// updateInitScript fetches parameters from a "coder_agent" to produce the
503
715
// agent script from environment variables.
504
716
func updateInitScript (resourceData * schema.ResourceData , i interface {}) diag.Diagnostics {
0 commit comments