25
25
# that are not directly used in the resource creation.
26
26
27
27
locals {
28
+ # Constants
29
+ default_workspace_name = " default"
30
+ root_space_id = " root"
31
+
28
32
_multi_instance_structure = var. root_module_structure == " MultiInstance"
29
33
30
34
# Read all stack files following the associated root_module_structue convention:
@@ -88,7 +92,7 @@ locals {
88
92
89
93
_single_instance_root_module_yaml_decoded = {
90
94
for module in local . enabled_root_modules : module => {
91
- " default " = yamldecode (file (" ${ path . root } /${ var . root_modules_path } /${ module } /stack.yaml" ))
95
+ (local . default_workspace_name ) = yamldecode (file (" ${ path . root } /${ var . root_modules_path } /${ module } /stack.yaml" ))
92
96
} if ! local. _multi_instance_structure
93
97
}
94
98
@@ -142,7 +146,7 @@ locals {
142
146
" root_module" = module,
143
147
144
148
# If default_tf_workspace_enabled is true, use "default" workspace, otherwise our file name is the workspace name
145
- " terraform_workspace" = try (content. automation_settings . default_tf_workspace_enabled , local. _default_tf_workspace_enabled) ? " default " : trimsuffix (file, " .yaml" ),
149
+ " terraform_workspace" = try (content. automation_settings . default_tf_workspace_enabled , local. _default_tf_workspace_enabled) ? local.default_workspace_name : trimsuffix (file, " .yaml" ),
146
150
147
151
# tfvars_file_name only pertains to MultiInstance, as SingleInstance expects consumers to use an auto.tfvars file.
148
152
# `yaml` is intentionally used here as we require Stack and `tfvars` config files to be named equally
@@ -276,13 +280,63 @@ locals {
276
280
space.name = > space.space_id
277
281
}
278
282
283
+ # Helper for property resolution with fallback to defaults
284
+ stack_property_resolver = {
285
+ for stack in local . stacks : stack => {
286
+ # Simple property resolution with fallback
287
+ administrative = try (local. stack_configs [stack ]. administrative , var. administrative )
288
+ autoretry = try (local. stack_configs [stack ]. autoretry , var. autoretry )
289
+ additional_project_globs = try (local. stack_configs [stack ]. additional_project_globs , var. additional_project_globs )
290
+ autodeploy = try (local. stack_configs [stack ]. autodeploy , var. autodeploy )
291
+ branch = try (local. stack_configs [stack ]. branch , var. branch )
292
+ enable_local_preview = try (local. stack_configs [stack ]. enable_local_preview , var. enable_local_preview )
293
+ enable_well_known_secret_masking = try (local. stack_configs [stack ]. enable_well_known_secret_masking , var. enable_well_known_secret_masking )
294
+ github_action_deploy = try (local. stack_configs [stack ]. github_action_deploy , var. github_action_deploy )
295
+ manage_state = try (local. stack_configs [stack ]. manage_state , var. manage_state )
296
+ protect_from_deletion = try (local. stack_configs [stack ]. protect_from_deletion , var. protect_from_deletion )
297
+ repository = try (local. stack_configs [stack ]. repository , var. repository )
298
+ runner_image = try (local. stack_configs [stack ]. runner_image , var. runner_image )
299
+ terraform_smart_sanitization = try (local. stack_configs [stack ]. terraform_smart_sanitization , var. terraform_smart_sanitization )
300
+ terraform_version = try (local. stack_configs [stack ]. terraform_version , var. terraform_version )
301
+ worker_pool_id = try (local. stack_configs [stack ]. worker_pool_id , var. worker_pool_id )
302
+
303
+ # AWS Integration properties
304
+ aws_integration_id = try (local. stack_configs [stack ]. aws_integration_id , var. aws_integration_id )
305
+
306
+ # Drift detection properties
307
+ drift_detection_ignore_state = try (local. stack_configs [stack ]. drift_detection_ignore_state , var. drift_detection_ignore_state )
308
+ drift_detection_reconcile = try (local. stack_configs [stack ]. drift_detection_reconcile , var. drift_detection_reconcile )
309
+ drift_detection_schedule = try (local. stack_configs [stack ]. drift_detection_schedule , var. drift_detection_schedule )
310
+ drift_detection_timezone = try (local. stack_configs [stack ]. drift_detection_timezone , var. drift_detection_timezone )
311
+
312
+ # Destructor properties
313
+ destructor_deactivated = try (local. stack_configs [stack ]. destructor_deactivated , var. destructor_deactivated )
314
+ }
315
+ }
316
+
317
+ # Helper for array merging with fallback
318
+ stack_array_merger = {
319
+ for stack in local . stacks : stack => {
320
+ after_apply = compact (concat (try (local. stack_configs [stack ]. after_apply , []), var. after_apply ))
321
+ after_destroy = compact (concat (try (local. stack_configs [stack ]. after_destroy , []), var. after_destroy ))
322
+ after_init = compact (concat (try (local. stack_configs [stack ]. after_init , []), var. after_init ))
323
+ after_perform = compact (concat (try (local. stack_configs [stack ]. after_perform , []), var. after_perform ))
324
+ after_plan = compact (concat (try (local. stack_configs [stack ]. after_plan , []), var. after_plan ))
325
+ after_run = compact (concat (try (local. stack_configs [stack ]. after_run , []), var. after_run ))
326
+ before_apply = compact (concat (try (local. stack_configs [stack ]. before_apply , []), var. before_apply ))
327
+ before_destroy = compact (concat (try (local. stack_configs [stack ]. before_destroy , []), var. before_destroy ))
328
+ before_perform = compact (concat (try (local. stack_configs [stack ]. before_perform , []), var. before_perform ))
329
+ before_plan = compact (concat (try (local. stack_configs [stack ]. before_plan , []), var. before_plan ))
330
+ }
331
+ }
332
+
279
333
resolved_space_ids = {
280
334
for stack in local . stacks : stack => coalesce (
281
335
try (local. stack_configs [stack ]. space_id , null ), # space_id always takes precedence since it's the most explicit
282
336
try (local. space_name_to_id [local . stack_configs [stack ]. space_name ], null ), # Then try to look up space_name from the stack.yaml to ID
283
337
var.space_id,
284
338
try (local. space_name_to_id [var . space_name ], null ), # Then try to look up the space_name global variable to ID
285
- " root " # If no space_id or space_name is provided, default to the root space
339
+ local.root_space_id # If no space_id or space_name is provided, default to the root space
286
340
)
287
341
}
288
342
@@ -292,12 +346,10 @@ locals {
292
346
for stack , config in local . stack_configs :
293
347
stack = > config if try (config. aws_integration_enabled , var. aws_integration_enabled )
294
348
}
295
-
296
349
drift_detection_stacks = {
297
350
for stack , config in local . stack_configs :
298
351
stack = > config if try (config. drift_detection_enabled , var. drift_detection_enabled )
299
352
}
300
-
301
353
destructor_stacks = {
302
354
for stack , config in local . stack_configs :
303
355
stack = > config if try (config. destructor_enabled , var. destructor_enabled )
@@ -333,38 +385,40 @@ module "deep" {
333
385
resource "spacelift_stack" "default" {
334
386
for_each = local. stacks
335
387
336
- administrative = coalesce (try (local. stack_configs [each . key ]. administrative , null ), var. administrative )
337
- additional_project_globs = try (local. stack_configs [each . key ]. additional_project_globs , var. additional_project_globs )
338
- after_apply = compact (concat (try (local. stack_configs [each . key ]. after_apply , []), var. after_apply ))
339
- after_destroy = compact (concat (try (local. stack_configs [each . key ]. after_destroy , []), var. after_destroy ))
340
- after_init = compact (concat (try (local. stack_configs [each . key ]. after_init , []), var. after_init ))
341
- after_perform = compact (concat (try (local. stack_configs [each . key ]. after_perform , []), var. after_perform ))
342
- after_plan = compact (concat (try (local. stack_configs [each . key ]. after_plan , []), var. after_plan ))
343
- after_run = compact (concat (try (local. stack_configs [each . key ]. after_run , []), var. after_run ))
344
- autodeploy = coalesce (try (local. stack_configs [each . key ]. autodeploy , null ), var. autodeploy )
345
- autoretry = try (local. stack_configs [each . key ]. autoretry , var. autoretry )
346
- before_apply = compact (coalesce (try (local. stack_configs [each . key ]. before_apply , []), var. before_apply ))
347
- before_destroy = compact (coalesce (try (local. stack_configs [each . key ]. before_destroy , []), var. before_destroy ))
388
+ administrative = local. stack_property_resolver [each . key ]. administrative
389
+ additional_project_globs = local. stack_property_resolver [each . key ]. additional_project_globs
390
+ after_apply = local. stack_array_merger [each . key ]. after_apply
391
+ after_destroy = local. stack_array_merger [each . key ]. after_destroy
392
+ after_init = local. stack_array_merger [each . key ]. after_init
393
+ after_perform = local. stack_array_merger [each . key ]. after_perform
394
+ after_plan = local. stack_array_merger [each . key ]. after_plan
395
+ after_run = local. stack_array_merger [each . key ]. after_run
396
+ autodeploy = local. stack_property_resolver [each . key ]. autodeploy
397
+ autoretry = local. stack_property_resolver [each . key ]. autoretry
398
+ before_apply = local. stack_array_merger [each . key ]. before_apply
399
+ before_destroy = local. stack_array_merger [each . key ]. before_destroy
400
+ # before_init is handled separately from other script arrays due to special tfvars logic
401
+ # See local.before_init for details on tfvars file copying and MultiInstance vs SingleInstance handling
348
402
before_init = local. before_init [each . key ]
349
- before_perform = compact ( coalesce ( try ( local. stack_configs [each . key ]. before_perform , []), var . before_perform ))
350
- before_plan = compact ( coalesce ( try ( local. stack_configs [each . key ]. before_plan , []), var . before_plan ))
351
- branch = try ( local. stack_configs [each . key ]. branch , var . branch )
352
- enable_local_preview = try ( local. stack_configs [each . key ]. enable_local_preview , var . enable_local_preview )
353
- enable_well_known_secret_masking = try ( local. stack_configs [each . key ]. enable_well_known_secret_masking , var . enable_well_known_secret_masking )
354
- github_action_deploy = try ( local. stack_configs [each . key ]. github_action_deploy , var . github_action_deploy )
403
+ before_perform = local. stack_array_merger [each . key ]. before_perform
404
+ before_plan = local. stack_array_merger [each . key ]. before_plan
405
+ branch = local. stack_property_resolver [each . key ]. branch
406
+ enable_local_preview = local. stack_property_resolver [each . key ]. enable_local_preview
407
+ enable_well_known_secret_masking = local. stack_property_resolver [each . key ]. enable_well_known_secret_masking
408
+ github_action_deploy = local. stack_property_resolver [each . key ]. github_action_deploy
355
409
labels = local. labels [each . key ]
356
- manage_state = try ( local. stack_configs [each . key ]. manage_state , var . manage_state )
410
+ manage_state = local. stack_property_resolver [each . key ]. manage_state
357
411
name = each. key
358
412
project_root = local. configs [each . key ]. project_root
359
- protect_from_deletion = try ( local. stack_configs [each . key ]. protect_from_deletion , var . protect_from_deletion )
360
- repository = try ( local. stack_configs [each . key ]. repository , var . repository )
361
- runner_image = try ( local. stack_configs [each . key ]. runner_image , var . runner_image )
413
+ protect_from_deletion = local. stack_property_resolver [each . key ]. protect_from_deletion
414
+ repository = local. stack_property_resolver [each . key ]. repository
415
+ runner_image = local. stack_property_resolver [each . key ]. runner_image
362
416
space_id = local. resolved_space_ids [each . key ]
363
- terraform_smart_sanitization = try ( local. stack_configs [each . key ]. terraform_smart_sanitization , var . terraform_smart_sanitization )
364
- terraform_version = try ( local. stack_configs [each . key ]. terraform_version , var . terraform_version )
417
+ terraform_smart_sanitization = local. stack_property_resolver [each . key ]. terraform_smart_sanitization
418
+ terraform_version = local. stack_property_resolver [each . key ]. terraform_version
365
419
terraform_workflow_tool = var. terraform_workflow_tool
366
420
terraform_workspace = local. configs [each . key ]. terraform_workspace
367
- worker_pool_id = try ( local. stack_configs [each . key ]. worker_pool_id , var . worker_pool_id )
421
+ worker_pool_id = local. stack_property_resolver [each . key ]. worker_pool_id
368
422
369
423
# Usage of `templatestring` requires OpenTofu 1.7 and Terraform 1.9 or later.
370
424
description = coalesce (
@@ -391,7 +445,7 @@ resource "spacelift_stack_destructor" "default" {
391
445
for_each = local. destructor_stacks
392
446
393
447
stack_id = spacelift_stack. default [each . key ]. id
394
- deactivated = try ( local. stack_configs [each . key ]. destructor_deactivated , var . destructor_deactivated )
448
+ deactivated = local. stack_property_resolver [each . key ]. destructor_deactivated
395
449
396
450
# `depends_on` should be used to make sure that all necessary resources (environment variables, roles, integrations, etc.)
397
451
# are still in place when the destruction run is executed.
@@ -405,7 +459,7 @@ resource "spacelift_stack_destructor" "default" {
405
459
resource "spacelift_aws_integration_attachment" "default" {
406
460
for_each = local. aws_integration_stacks
407
461
408
- integration_id = try ( local. stack_configs [each . key ]. aws_integration_id , var . aws_integration_id )
462
+ integration_id = local. stack_property_resolver [each . key ]. aws_integration_id
409
463
stack_id = spacelift_stack. default [each . key ]. id
410
464
read = var. aws_integration_attachment_read
411
465
write = var. aws_integration_attachment_write
@@ -415,14 +469,14 @@ resource "spacelift_drift_detection" "default" {
415
469
for_each = local. drift_detection_stacks
416
470
417
471
stack_id = spacelift_stack. default [each . key ]. id
418
- ignore_state = try ( local. stack_configs [each . key ]. drift_detection_ignore_state , var . drift_detection_ignore_state )
419
- reconcile = try ( local. stack_configs [each . key ]. drift_detection_reconcile , var . drift_detection_reconcile )
420
- schedule = try ( local. stack_configs [each . key ]. drift_detection_schedule , var . drift_detection_schedule )
421
- timezone = try ( local. stack_configs [each . key ]. drift_detection_timezone , var . drift_detection_timezone )
472
+ ignore_state = local. stack_property_resolver [each . key ]. drift_detection_ignore_state
473
+ reconcile = local. stack_property_resolver [each . key ]. drift_detection_reconcile
474
+ schedule = local. stack_property_resolver [each . key ]. drift_detection_schedule
475
+ timezone = local. stack_property_resolver [each . key ]. drift_detection_timezone
422
476
423
477
lifecycle {
424
478
precondition {
425
- condition = alltrue ([for schedule in try ( local. stack_configs [each . key ]. drift_detection_schedule , var . drift_detection_schedule ) : can (regex (" ^([0-9,\\ -*/]+\\ s+){4}[0-9,\\ -*/]+$" , schedule))])
479
+ condition = alltrue ([for schedule in local . stack_property_resolver [each . key ]. drift_detection_schedule : can (regex (" ^([0-9,\\ -*/]+\\ s+){4}[0-9,\\ -*/]+$" , schedule))])
426
480
error_message = " Invalid cron schedule format for drift detection"
427
481
}
428
482
}
0 commit comments