@@ -17,6 +17,46 @@ import (
1717 u "github.com/cloudposse/atmos/pkg/utils"
1818)
1919
20+ // backendConfig holds extracted backend configuration from a component section.
21+ type backendConfig struct {
22+ BackendSection map [string ]any
23+ BackendType string
24+ Err error
25+ }
26+
27+ // extractBackendConfig extracts and validates backend configuration from a component section.
28+ func extractBackendConfig (componentSection map [string ]any ) backendConfig {
29+ backendSection , ok := componentSection [cfg .BackendSectionName ].(map [string ]any )
30+ if ! ok {
31+ return backendConfig {Err : errUtils .ErrBackendSectionMissing }
32+ }
33+
34+ backendType , ok := componentSection [cfg .BackendTypeSectionName ].(string )
35+ if ! ok {
36+ return backendConfig {Err : errUtils .ErrBackendTypeMissing }
37+ }
38+
39+ // Check if backend section is empty for backends that require configuration.
40+ // The "local" backend can work without any configuration, but remote backends
41+ // like s3, gcs, azurerm, and cloud require at least some configuration.
42+ if len (backendSection ) == 0 && backendType != cfg .BackendTypeLocal {
43+ return backendConfig {Err : errUtils .ErrBackendConfigEmpty }
44+ }
45+
46+ return backendConfig {
47+ BackendSection : backendSection ,
48+ BackendType : backendType ,
49+ }
50+ }
51+
52+ // checkBackendTypeAfterProcessing validates that backend_type is not empty after template processing.
53+ func checkBackendTypeAfterProcessing (backendType string ) error {
54+ if backendType == "" {
55+ return errUtils .ErrBackendTypeEmptyAfterRender
56+ }
57+ return nil
58+ }
59+
2060// ExecuteTerraformGenerateBackendsCmd executes `terraform generate backends` command.
2161func ExecuteTerraformGenerateBackendsCmd (cmd * cobra.Command , args []string ) error {
2262 defer perf .Track (nil , "exec.ExecuteTerraformGenerateBackendsCmd" )()
@@ -132,15 +172,16 @@ func ExecuteTerraformGenerateBackends(
132172 }
133173 }
134174
135- // Component backend
136- if backendSection , ok = componentSection [cfg .BackendSectionName ].(map [string ]any ); ! ok {
137- continue
138- }
139-
140- // Backend type
141- if backendTypeSection , ok = componentSection [cfg .BackendTypeSectionName ].(string ); ! ok {
175+ // Extract backend configuration.
176+ backend := extractBackendConfig (componentSection )
177+ if backend .Err != nil {
178+ log .Warn ("Skipping backend generation: " + backend .Err .Error ()+ ". " +
179+ "Set 'components.terraform.auto_generate_backend_file: false' in atmos.yaml to disable." ,
180+ "component" , componentName , "stack" , stackFileName )
142181 continue
143182 }
183+ backendSection = backend .BackendSection
184+ backendTypeSection = backend .BackendType
144185
145186 if varsSection , ok = componentSection [cfg .VarsSectionName ].(map [string ]any ); ! ok {
146187 varsSection = map [string ]any {}
@@ -295,6 +336,14 @@ func ExecuteTerraformGenerateBackends(
295336 backendTypeSection = i
296337 }
297338
339+ // Skip if backend_type is empty after template processing.
340+ if err := checkBackendTypeAfterProcessing (backendTypeSection ); err != nil {
341+ log .Warn ("Skipping backend generation: " + err .Error ()+ ". " +
342+ "Set 'components.terraform.auto_generate_backend_file: false' in atmos.yaml to disable." ,
343+ "component" , componentName , "stack" , stackName )
344+ continue
345+ }
346+
298347 var backendFilePath string
299348 var backendFileAbsolutePath string
300349
0 commit comments