@@ -25,6 +25,7 @@ import (
25
25
26
26
"github.com/hashicorp/terraform-plugin-framework/attr"
27
27
"github.com/hashicorp/terraform-plugin-framework/diag"
28
+ "github.com/hashicorp/terraform-plugin-framework/path"
28
29
"github.com/hashicorp/terraform-plugin-framework/resource"
29
30
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
30
31
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
@@ -160,7 +161,6 @@ func (r *CachedImageResource) Schema(ctx context.Context, req resource.SchemaReq
160
161
MarkdownDescription : "(Envbuilder option) Terminates upon a build failure. This is handy when preferring the FALLBACK_IMAGE in cases where no devcontainer.json or image is provided. However, it ensures that the container stops if the build process encounters an error." ,
161
162
Optional : true ,
162
163
},
163
- // TODO(mafredri): Map vs List? Support both?
164
164
"extra_env" : schema.MapAttribute {
165
165
MarkdownDescription : "Extra environment variables to set for the container. This may include envbuilder options." ,
166
166
ElementType : types .StringType ,
@@ -293,6 +293,135 @@ func (r *CachedImageResource) Configure(ctx context.Context, req resource.Config
293
293
r .client = client
294
294
}
295
295
296
+ // setComputedEnv sets data.Env and data.EnvMap based on the values of the
297
+ // other fields in the model.
298
+ func (data * CachedImageResourceModel ) setComputedEnv (ctx context.Context ) diag.Diagnostics {
299
+ env := make (map [string ]string )
300
+
301
+ env ["ENVBUILDER_CACHE_REPO" ] = tfValueToString (data .CacheRepo )
302
+ env ["ENVBUILDER_GIT_URL" ] = tfValueToString (data .GitURL )
303
+
304
+ if ! data .BaseImageCacheDir .IsNull () {
305
+ env ["ENVBUILDER_BASE_IMAGE_CACHE_DIR" ] = tfValueToString (data .BaseImageCacheDir )
306
+ }
307
+
308
+ if ! data .BuildContextPath .IsNull () {
309
+ env ["ENVBUILDER_BUILD_CONTEXT_PATH" ] = tfValueToString (data .BuildContextPath )
310
+ }
311
+
312
+ if ! data .CacheTTLDays .IsNull () {
313
+ env ["ENVBUILDER_CACHE_TTL_DAYS" ] = tfValueToString (data .CacheTTLDays )
314
+ }
315
+
316
+ if ! data .DevcontainerDir .IsNull () {
317
+ env ["ENVBUILDER_DEVCONTAINER_DIR" ] = tfValueToString (data .DevcontainerDir )
318
+ }
319
+
320
+ if ! data .DevcontainerJSONPath .IsNull () {
321
+ env ["ENVBUILDER_DEVCONTAINER_JSON_PATH" ] = tfValueToString (data .DevcontainerJSONPath )
322
+ }
323
+
324
+ if ! data .DockerfilePath .IsNull () {
325
+ env ["ENVBUILDER_DOCKERFILE_PATH" ] = tfValueToString (data .DockerfilePath )
326
+ }
327
+
328
+ if ! data .DockerConfigBase64 .IsNull () {
329
+ env ["ENVBUILDER_DOCKER_CONFIG_BASE64" ] = tfValueToString (data .DockerConfigBase64 )
330
+ }
331
+
332
+ if ! data .ExitOnBuildFailure .IsNull () {
333
+ env ["ENVBUILDER_EXIT_ON_BUILD_FAILURE" ] = tfValueToString (data .ExitOnBuildFailure )
334
+ }
335
+
336
+ if ! data .FallbackImage .IsNull () {
337
+ env ["ENVBUILDER_FALLBACK_IMAGE" ] = tfValueToString (data .FallbackImage )
338
+ }
339
+
340
+ if ! data .GitCloneDepth .IsNull () {
341
+ env ["ENVBUILDER_GIT_CLONE_DEPTH" ] = tfValueToString (data .GitCloneDepth )
342
+ }
343
+
344
+ if ! data .GitCloneSingleBranch .IsNull () {
345
+ env ["ENVBUILDER_GIT_CLONE_SINGLE_BRANCH" ] = tfValueToString (data .GitCloneSingleBranch )
346
+ }
347
+
348
+ if ! data .GitHTTPProxyURL .IsNull () {
349
+ env ["ENVBUILDER_GIT_HTTP_PROXY_URL" ] = tfValueToString (data .GitHTTPProxyURL )
350
+ }
351
+
352
+ if ! data .GitSSHPrivateKeyPath .IsNull () {
353
+ env ["ENVBUILDER_GIT_SSH_PRIVATE_KEY_PATH" ] = tfValueToString (data .GitSSHPrivateKeyPath )
354
+ }
355
+
356
+ if ! data .GitUsername .IsNull () {
357
+ env ["ENVBUILDER_GIT_USERNAME" ] = tfValueToString (data .GitUsername )
358
+ }
359
+
360
+ if ! data .GitPassword .IsNull () {
361
+ env ["ENVBUILDER_GIT_PASSWORD" ] = tfValueToString (data .GitPassword )
362
+ }
363
+
364
+ if ! data .IgnorePaths .IsNull () {
365
+ env ["ENVBUILDER_IGNORE_PATHS" ] = strings .Join (tfListToStringSlice (data .IgnorePaths ), "," )
366
+ }
367
+
368
+ if ! data .Insecure .IsNull () {
369
+ env ["ENVBUILDER_INSECURE" ] = tfValueToString (data .Insecure )
370
+ }
371
+
372
+ // Default to remote build mode.
373
+ if data .RemoteRepoBuildMode .IsNull () {
374
+ env ["ENVBUILDER_REMOTE_REPO_BUILD_MODE" ] = "true"
375
+ } else {
376
+ env ["ENVBUILDER_REMOTE_REPO_BUILD_MODE" ] = tfValueToString (data .RemoteRepoBuildMode )
377
+ }
378
+
379
+ if ! data .SSLCertBase64 .IsNull () {
380
+ env ["ENVBUILDER_SSL_CERT_BASE64" ] = tfValueToString (data .SSLCertBase64 )
381
+ }
382
+
383
+ if ! data .Verbose .IsNull () {
384
+ env ["ENVBUILDER_VERBOSE" ] = tfValueToString (data .Verbose )
385
+ }
386
+
387
+ if ! data .WorkspaceFolder .IsNull () {
388
+ env ["ENVBUILDER_WORKSPACE_FOLDER" ] = tfValueToString (data .WorkspaceFolder )
389
+ }
390
+
391
+ // Do ExtraEnv last so that it can override any other values.
392
+ // With one exception: ENVBUILDER_CACHE_REPO and ENVBUILDER_GIT_URL are required and should not be overridden.
393
+ // Other values set by the provider may be overridden, but will generate a warning.
394
+ var diag , ds diag.Diagnostics
395
+ if ! data .ExtraEnv .IsNull () {
396
+ for key , elem := range data .ExtraEnv .Elements () {
397
+ switch key {
398
+ // These are required and should not be overridden.
399
+ case "ENVBUILDER_CACHE_REPO" , "ENVBUILDER_GIT_URL" :
400
+ diag .AddAttributeWarning (path .Root ("extra_env" ),
401
+ "Cannot override required environment variable" ,
402
+ fmt .Sprintf ("The key %q in extra_env cannot be overridden." , key ),
403
+ )
404
+ default :
405
+ if _ , ok := env [key ]; ok {
406
+ // This is a warning because it's possible that the user wants to override
407
+ // a value set by the provider.
408
+ diag .AddAttributeWarning (path .Root ("extra_env" ),
409
+ "Overriding provider environment variable" ,
410
+ fmt .Sprintf ("The key %q in extra_env overrides an environment variable set by the provider." , key ),
411
+ )
412
+ }
413
+ env [key ] = tfValueToString (elem )
414
+ }
415
+ }
416
+ }
417
+
418
+ data .EnvMap , ds = basetypes .NewMapValueFrom (ctx , types .StringType , env )
419
+ diag = append (diag , ds ... )
420
+ data .Env , ds = basetypes .NewListValueFrom (ctx , types .StringType , sortedKeyValues (env ))
421
+ diag = append (diag , ds ... )
422
+ return diag
423
+ }
424
+
296
425
func (r * CachedImageResource ) Read (ctx context.Context , req resource.ReadRequest , resp * resource.ReadResponse ) {
297
426
var data CachedImageResourceModel
298
427
@@ -350,35 +479,7 @@ func (r *CachedImageResource) Read(ctx context.Context, req resource.ReadRequest
350
479
data .Exists = types .BoolValue (true )
351
480
352
481
// Set the expected environment variables.
353
- env := make (map [string ]string )
354
- for key , elem := range data .ExtraEnv .Elements () {
355
- env [key ] = tfValueToString (elem )
356
- }
357
-
358
- env ["ENVBUILDER_CACHE_REPO" ] = tfValueToString (data .CacheRepo )
359
- env ["ENVBUILDER_GIT_URL" ] = tfValueToString (data .GitURL )
360
-
361
- if ! data .CacheTTLDays .IsNull () {
362
- env ["ENVBUILDER_CACHE_TTL_DAYS" ] = tfValueToString (data .CacheTTLDays )
363
- }
364
- if ! data .GitUsername .IsNull () {
365
- env ["ENVBUILDER_GIT_USERNAME" ] = tfValueToString (data .GitUsername )
366
- }
367
- if ! data .GitPassword .IsNull () {
368
- env ["ENVBUILDER_GIT_PASSWORD" ] = tfValueToString (data .GitPassword )
369
- }
370
- // Default to remote build mode.
371
- if data .RemoteRepoBuildMode .IsNull () {
372
- env ["ENVBUILDER_REMOTE_REPO_BUILD_MODE" ] = "true"
373
- } else {
374
- env ["ENVBUILDER_REMOTE_REPO_BUILD_MODE" ] = tfValueToString (data .RemoteRepoBuildMode )
375
- }
376
-
377
- var diag diag.Diagnostics
378
- data .EnvMap , diag = basetypes .NewMapValueFrom (ctx , types .StringType , env )
379
- resp .Diagnostics .Append (diag ... )
380
- data .Env , diag = basetypes .NewListValueFrom (ctx , types .StringType , sortedKeyValues (env ))
381
- resp .Diagnostics .Append (diag ... )
482
+ resp .Diagnostics .Append (data .setComputedEnv (ctx )... )
382
483
383
484
resp .Diagnostics .Append (resp .State .Set (ctx , & data )... )
384
485
}
@@ -415,36 +516,9 @@ func (r *CachedImageResource) Create(ctx context.Context, req resource.CreateReq
415
516
data .Image = types .StringValue (fmt .Sprintf ("%s@%s" , data .CacheRepo .ValueString (), digest ))
416
517
data .ID = types .StringValue (digest .String ())
417
518
}
418
- // Compute the env attribute from the config map.
419
- env := make (map [string ]string )
420
- for key , elem := range data .ExtraEnv .Elements () {
421
- env [key ] = tfValueToString (elem )
422
- }
423
519
424
- env ["ENVBUILDER_CACHE_REPO" ] = tfValueToString (data .CacheRepo )
425
- env ["ENVBUILDER_GIT_URL" ] = tfValueToString (data .GitURL )
426
-
427
- if ! data .CacheTTLDays .IsNull () {
428
- env ["ENVBUILDER_CACHE_TTL_DAYS" ] = tfValueToString (data .CacheTTLDays )
429
- }
430
- if ! data .GitUsername .IsNull () {
431
- env ["ENVBUILDER_GIT_USERNAME" ] = tfValueToString (data .GitUsername )
432
- }
433
- if ! data .GitPassword .IsNull () {
434
- env ["ENVBUILDER_GIT_PASSWORD" ] = tfValueToString (data .GitPassword )
435
- }
436
- // Default to remote build mode.
437
- if data .RemoteRepoBuildMode .IsNull () {
438
- env ["ENVBUILDER_REMOTE_REPO_BUILD_MODE" ] = "true"
439
- } else {
440
- env ["ENVBUILDER_REMOTE_REPO_BUILD_MODE" ] = tfValueToString (data .RemoteRepoBuildMode )
441
- }
442
-
443
- var diag diag.Diagnostics
444
- data .EnvMap , diag = basetypes .NewMapValueFrom (ctx , types .StringType , env )
445
- resp .Diagnostics .Append (diag ... )
446
- data .Env , diag = basetypes .NewListValueFrom (ctx , types .StringType , sortedKeyValues (env ))
447
- resp .Diagnostics .Append (diag ... )
520
+ // Set the expected environment variables.
521
+ resp .Diagnostics .Append (data .setComputedEnv (ctx )... )
448
522
449
523
// Save data into Terraform state
450
524
resp .Diagnostics .Append (resp .State .Set (ctx , & data )... )
@@ -556,6 +630,7 @@ func (r *CachedImageResource) runCacheProbe(ctx context.Context, data CachedImag
556
630
Insecure : data .Insecure .ValueBool (), // might have internal CAs?
557
631
IgnorePaths : tfListToStringSlice (data .IgnorePaths ), // may need to be specified?
558
632
// The below options are not relevant and are set to their zero value explicitly.
633
+ // They must be set by extra_env.
559
634
CoderAgentSubsystem : nil ,
560
635
CoderAgentToken : "" ,
561
636
CoderAgentURL : "" ,
0 commit comments