Skip to content

Commit f750732

Browse files
authored
Merge branch 'main' into version-constraint
2 parents a186607 + 40c4c0f commit f750732

File tree

14 files changed

+594
-24
lines changed

14 files changed

+594
-24
lines changed

errors/errors.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,19 @@ var (
111111
ErrAzurePermissionDenied = errors.New("permission denied accessing Azure blob")
112112

113113
// Azure authentication errors.
114-
ErrAzureOIDClaimNotFound = errors.New("oid claim not found in token")
115-
ErrAzureUsernameClaimNotFound = errors.New("no username claim found in token (tried upn, unique_name, email)")
116-
ErrAzureInvalidJWTFormat = errors.New("invalid JWT format")
117-
ErrAzureExpirationTimeEmpty = errors.New("expiration time is empty")
118-
ErrAzureTimeParseFailure = errors.New("unable to parse time: tried RFC3339, local time formats, and Unix timestamp")
119-
ErrAzureNoAccountsInCache = errors.New("no accounts found in cache")
120-
ErrAzureNoAccountForTenant = errors.New("no account found for tenant")
121-
ErrBackendConfigRequired = errors.New("backend configuration is required")
114+
ErrAzureOIDClaimNotFound = errors.New("oid claim not found in token")
115+
ErrAzureUsernameClaimNotFound = errors.New("no username claim found in token (tried upn, unique_name, email)")
116+
ErrAzureInvalidJWTFormat = errors.New("invalid JWT format")
117+
ErrAzureExpirationTimeEmpty = errors.New("expiration time is empty")
118+
ErrAzureTimeParseFailure = errors.New("unable to parse time: tried RFC3339, local time formats, and Unix timestamp")
119+
ErrAzureNoAccountsInCache = errors.New("no accounts found in cache")
120+
ErrAzureNoAccountForTenant = errors.New("no account found for tenant")
121+
ErrBackendConfigRequired = errors.New("backend configuration is required")
122+
ErrBackendTypeRequired = errors.New("backend_type is required")
123+
ErrBackendSectionMissing = errors.New("no 'backend' section configured")
124+
ErrBackendTypeMissing = errors.New("no 'backend_type' configured")
125+
ErrBackendTypeEmptyAfterRender = errors.New("'backend_type' is empty after template processing")
126+
ErrBackendConfigEmpty = errors.New("'backend' section is empty but 'backend_type' requires configuration")
122127

123128
// Git-related errors.
124129
ErrGitNotAvailable = errors.New("git must be available and on the PATH")

internal/exec/terraform_generate_backends.go

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
2161
func 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

Comments
 (0)