Skip to content

Commit d11bdf6

Browse files
authored
Refactor backend error strings as custom errors or pre-made diagnostics (#37762)
* Replace `errBackendLocalRead` constant with custom error of same name * Replace `errBackendNoExistingWorkspaces` constant with custom error of same name * Replace `errBackendMigrateLocalDelete` constant with custom error of same name * Replace `errBackendNewUnknown` constant with custom error of same name * Replace `errBackendSavedUnknown` constant with custom error of same name * Replace `errBackendClearSaved` constant with custom error of same name * Replace `errBackendInit` constant with custom error of same name * Replace `errBackendInitCloud` constant with custom error of same name * Replace `errBackendWriteSaved` constant with custom error of same name * Move `migrateOrReconfigDiag` next to custom errors * Replace `errBackendInit` custom error with `func errBackendInitDiag` for creating diagnostics directly * Replace `errBackendInitCloud` custom error with `func errBackendInitCloudDiag` for creating diagnostics directly * Replace `errBackendWriteSaved` custom error with `func errBackendWriteSavedDiag` for creating diagnostics directly * Add new usage of errBackendWriteSavedDiag; this is another place where failing to write to backend state files happens * Add godoc comments * Ensure errors aren't repeated in terminal output, and ensure warnings are not lost.
1 parent bffba7f commit d11bdf6

File tree

2 files changed

+214
-154
lines changed

2 files changed

+214
-154
lines changed

internal/command/meta_backend.go

Lines changed: 26 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ func (m *Meta) selectWorkspace(b backend.Backend) error {
276276
log.Printf("[TRACE] Meta.selectWorkspace: selecting the new HCP Terraform workspace requested by the user (%s)", name)
277277
return m.SetWorkspace(name)
278278
} else {
279-
return errors.New(strings.TrimSpace(errBackendNoExistingWorkspaces))
279+
return &errBackendNoExistingWorkspaces{}
280280
}
281281
}
282282

@@ -341,7 +341,7 @@ func (m *Meta) BackendForLocalPlan(settings plans.Backend) (backendrun.Operation
341341

342342
f := backendInit.Backend(settings.Type)
343343
if f == nil {
344-
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), settings.Type))
344+
diags = diags.Append(errBackendSavedUnknown{settings.Type})
345345
return nil, diags
346346
}
347347
b := f()
@@ -751,11 +751,7 @@ func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Di
751751

752752
initReason := fmt.Sprintf("Unsetting the previously set backend %q", s.Backend.Type)
753753
if !opts.Init {
754-
diags = diags.Append(tfdiags.Sourceless(
755-
tfdiags.Error,
756-
"Backend initialization required, please run \"terraform init\"",
757-
fmt.Sprintf(strings.TrimSpace(errBackendInit), initReason),
758-
))
754+
diags = diags.Append(errBackendInitDiag(initReason))
759755
return nil, diags
760756
}
761757

@@ -787,18 +783,10 @@ func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Di
787783
if !opts.Init {
788784
if backendConfig.Type == "cloud" {
789785
initReason := "Initial configuration of HCP Terraform or Terraform Enterprise"
790-
diags = diags.Append(tfdiags.Sourceless(
791-
tfdiags.Error,
792-
"HCP Terraform or Terraform Enterprise initialization required: please run \"terraform init\"",
793-
fmt.Sprintf(strings.TrimSpace(errBackendInitCloud), initReason),
794-
))
786+
diags = diags.Append(errBackendInitCloudDiag(initReason))
795787
} else {
796788
initReason := fmt.Sprintf("Initial configuration of the requested backend %q", backendConfig.Type)
797-
diags = diags.Append(tfdiags.Sourceless(
798-
tfdiags.Error,
799-
"Backend initialization required, please run \"terraform init\"",
800-
fmt.Sprintf(strings.TrimSpace(errBackendInit), initReason),
801-
))
789+
diags = diags.Append(errBackendInitDiag(initReason))
802790
}
803791
return nil, diags
804792
}
@@ -979,23 +967,11 @@ func (m *Meta) determineInitReason(previousBackendType string, currentBackendTyp
979967
var diags tfdiags.Diagnostics
980968
switch cloudMode {
981969
case cloud.ConfigChangeInPlace:
982-
diags = diags.Append(tfdiags.Sourceless(
983-
tfdiags.Error,
984-
"HCP Terraform or Terraform Enterprise initialization required: please run \"terraform init\"",
985-
fmt.Sprintf(strings.TrimSpace(errBackendInitCloud), initReason),
986-
))
970+
diags = diags.Append(errBackendInitCloudDiag(initReason))
987971
case cloud.ConfigMigrationIn:
988-
diags = diags.Append(tfdiags.Sourceless(
989-
tfdiags.Error,
990-
"HCP Terraform or Terraform Enterprise initialization required: please run \"terraform init\"",
991-
fmt.Sprintf(strings.TrimSpace(errBackendInitCloud), initReason),
992-
))
972+
diags = diags.Append(errBackendInitCloudDiag(initReason))
993973
default:
994-
diags = diags.Append(tfdiags.Sourceless(
995-
tfdiags.Error,
996-
"Backend initialization required: please run \"terraform init\"",
997-
fmt.Sprintf(strings.TrimSpace(errBackendInit), initReason),
998-
))
974+
diags = diags.Append(errBackendInitDiag(initReason))
999975
}
1000976

1001977
return diags
@@ -1035,7 +1011,7 @@ func (m *Meta) backendFromState(_ context.Context) (backend.Backend, tfdiags.Dia
10351011
}
10361012
f := backendInit.Backend(s.Backend.Type)
10371013
if f == nil {
1038-
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type))
1014+
diags = diags.Append(errBackendSavedUnknown{s.Backend.Type})
10391015
return nil, diags
10401016
}
10411017
b := f()
@@ -1158,11 +1134,11 @@ func (m *Meta) backend_c_r_S(
11581134
// Remove the stored metadata
11591135
s.Backend = nil
11601136
if err := sMgr.WriteState(s); err != nil {
1161-
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
1137+
diags = diags.Append(errBackendClearSaved{err})
11621138
return nil, diags
11631139
}
11641140
if err := sMgr.PersistState(); err != nil {
1165-
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
1141+
diags = diags.Append(errBackendClearSaved{err})
11661142
return nil, diags
11671143
}
11681144

@@ -1195,21 +1171,22 @@ func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *clistate.Local
11951171
}
11961172

11971173
workspaces, wDiags := localB.Workspaces()
1198-
diags = diags.Append(wDiags)
11991174
if wDiags.HasErrors() {
1200-
diags = diags.Append(fmt.Errorf(errBackendLocalRead, wDiags.Err()))
1175+
diags = diags.Append(wDiags.Warnings())
1176+
diags = diags.Append(&errBackendLocalRead{wDiags.Err()})
12011177
return nil, diags
12021178
}
12031179

12041180
var localStates []statemgr.Full
12051181
for _, workspace := range workspaces {
12061182
localState, sDiags := localB.StateMgr(workspace)
12071183
if sDiags.HasErrors() {
1208-
diags = diags.Append(fmt.Errorf(errBackendLocalRead, sDiags.Err()))
1184+
diags = diags.Append(sDiags.Warnings())
1185+
diags = diags.Append(&errBackendLocalRead{sDiags.Err()})
12091186
return nil, diags
12101187
}
12111188
if err := localState.RefreshState(); err != nil {
1212-
diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
1189+
diags = diags.Append(&errBackendLocalRead{err})
12131190
return nil, diags
12141191
}
12151192

@@ -1268,11 +1245,11 @@ func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *clistate.Local
12681245
for _, localState := range localStates {
12691246
// We always delete the local state, unless that was our new state too.
12701247
if err := localState.WriteState(nil); err != nil {
1271-
diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
1248+
diags = diags.Append(&errBackendMigrateLocalDelete{err})
12721249
return nil, diags
12731250
}
12741251
if err := localState.PersistState(nil); err != nil {
1275-
diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
1252+
diags = diags.Append(&errBackendMigrateLocalDelete{err})
12761253
return nil, diags
12771254
}
12781255
}
@@ -1326,11 +1303,11 @@ func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *clistate.Local
13261303
}
13271304

13281305
if err := sMgr.WriteState(s); err != nil {
1329-
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
1306+
diags = diags.Append(errBackendWriteSavedDiag(err))
13301307
return nil, diags
13311308
}
13321309
if err := sMgr.PersistState(); err != nil {
1333-
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
1310+
diags = diags.Append(errBackendWriteSavedDiag(err))
13341311
return nil, diags
13351312
}
13361313

@@ -1456,11 +1433,11 @@ func (m *Meta) backend_C_r_S_changed(c *configs.Backend, cHash int, sMgr *clista
14561433
}
14571434

14581435
if err := sMgr.WriteState(s); err != nil {
1459-
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
1436+
diags = diags.Append(errBackendWriteSavedDiag(err))
14601437
return nil, diags
14611438
}
14621439
if err := sMgr.PersistState(); err != nil {
1463-
diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
1440+
diags = diags.Append(errBackendWriteSavedDiag(err))
14641441
return nil, diags
14651442
}
14661443

@@ -1489,7 +1466,7 @@ func (m *Meta) savedBackend(sMgr *clistate.LocalState) (backend.Backend, tfdiags
14891466
// Get the backend
14901467
f := backendInit.Backend(s.Backend.Type)
14911468
if f == nil {
1492-
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type))
1469+
diags = diags.Append(errBackendSavedUnknown{s.Backend.Type})
14931470
return nil, diags
14941471
}
14951472
b := f()
@@ -1543,8 +1520,9 @@ func (m *Meta) updateSavedBackendHash(cHash int, sMgr *clistate.LocalState) tfdi
15431520
if s.Backend.Hash != uint64(cHash) {
15441521
s.Backend.Hash = uint64(cHash)
15451522
if err := sMgr.WriteState(s); err != nil {
1546-
diags = diags.Append(err)
1523+
diags = diags.Append(errBackendWriteSavedDiag(err))
15471524
}
1525+
// No need to call PersistState as it's a no-op
15481526
}
15491527

15501528
return diags
@@ -1788,7 +1766,7 @@ func (m *Meta) backendInitFromConfig(c *configs.Backend) (backend.Backend, cty.V
17881766
// Get the backend
17891767
f := backendInit.Backend(c.Type)
17901768
if f == nil {
1791-
diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendNewUnknown), c.Type))
1769+
diags = diags.Append(errBackendNewUnknown{c.Type})
17921770
return nil, cty.NilVal, diags
17931771
}
17941772
b := f()
@@ -2149,105 +2127,6 @@ func (m *Meta) GetStateStoreProviderFactory(config *configs.StateStore, locks *d
21492127
// Output constants and initialization code
21502128
//-------------------------------------------------------------------
21512129

2152-
const errBackendLocalRead = `
2153-
Error reading local state: %s
2154-
2155-
Terraform is trying to read your local state to determine if there is
2156-
state to migrate to your newly configured backend. Terraform can't continue
2157-
without this check because that would risk losing state. Please resolve the
2158-
error above and try again.
2159-
`
2160-
2161-
const errBackendMigrateLocalDelete = `
2162-
Error deleting local state after migration: %s
2163-
2164-
Your local state is deleted after successfully migrating it to the newly
2165-
configured backend. As part of the deletion process, a backup is made at
2166-
the standard backup path unless explicitly asked not to. To cleanly operate
2167-
with a backend, we must delete the local state file. Please resolve the
2168-
issue above and retry the command.
2169-
`
2170-
2171-
const errBackendNewUnknown = `
2172-
The backend %q could not be found.
2173-
2174-
This is the backend specified in your Terraform configuration file.
2175-
This error could be a simple typo in your configuration, but it can also
2176-
be caused by using a Terraform version that doesn't support the specified
2177-
backend type. Please check your configuration and your Terraform version.
2178-
2179-
If you'd like to run Terraform and store state locally, you can fix this
2180-
error by removing the backend configuration from your configuration.
2181-
`
2182-
2183-
const errBackendNoExistingWorkspaces = `
2184-
No existing workspaces.
2185-
2186-
Use the "terraform workspace" command to create and select a new workspace.
2187-
If the backend already contains existing workspaces, you may need to update
2188-
the backend configuration.
2189-
`
2190-
2191-
const errBackendSavedUnknown = `
2192-
The backend %q could not be found.
2193-
2194-
This is the backend that this Terraform environment is configured to use
2195-
both in your configuration and saved locally as your last-used backend.
2196-
If it isn't found, it could mean an alternate version of Terraform was
2197-
used with this configuration. Please use the proper version of Terraform that
2198-
contains support for this backend.
2199-
2200-
If you'd like to force remove this backend, you must update your configuration
2201-
to not use the backend and run "terraform init" (or any other command) again.
2202-
`
2203-
2204-
const errBackendClearSaved = `
2205-
Error clearing the backend configuration: %s
2206-
2207-
Terraform removes the saved backend configuration when you're removing a
2208-
configured backend. This must be done so future Terraform runs know to not
2209-
use the backend configuration. Please look at the error above, resolve it,
2210-
and try again.
2211-
`
2212-
2213-
const errBackendInit = `
2214-
Reason: %s
2215-
2216-
The "backend" is the interface that Terraform uses to store state,
2217-
perform operations, etc. If this message is showing up, it means that the
2218-
Terraform configuration you're using is using a custom configuration for
2219-
the Terraform backend.
2220-
2221-
Changes to backend configurations require reinitialization. This allows
2222-
Terraform to set up the new configuration, copy existing state, etc. Please run
2223-
"terraform init" with either the "-reconfigure" or "-migrate-state" flags to
2224-
use the current configuration.
2225-
2226-
If the change reason above is incorrect, please verify your configuration
2227-
hasn't changed and try again. At this point, no changes to your existing
2228-
configuration or state have been made.
2229-
`
2230-
2231-
const errBackendInitCloud = `
2232-
Reason: %s.
2233-
2234-
Changes to the HCP Terraform configuration block require reinitialization, to discover any changes to the available workspaces.
2235-
2236-
To re-initialize, run:
2237-
terraform init
2238-
2239-
Terraform has not yet made changes to your existing configuration or state.
2240-
`
2241-
2242-
const errBackendWriteSaved = `
2243-
Error saving the backend configuration: %s
2244-
2245-
Terraform saves the complete backend configuration in a local file for
2246-
configuring the backend on future operations. This cannot be disabled. Errors
2247-
are usually due to simple file permission errors. Please look at the error
2248-
above, resolve it, and try again.
2249-
`
2250-
22512130
const outputBackendMigrateChange = `
22522131
Terraform detected that the backend type changed from %q to %q.
22532132
`
@@ -2280,10 +2159,3 @@ const successBackendSet = `
22802159
Successfully configured the backend %q! Terraform will automatically
22812160
use this backend unless the backend configuration changes.
22822161
`
2283-
2284-
var migrateOrReconfigDiag = tfdiags.Sourceless(
2285-
tfdiags.Error,
2286-
"Backend configuration changed",
2287-
"A change in the backend configuration has been detected, which may require migrating existing state.\n\n"+
2288-
"If you wish to attempt automatic migration of the state, use \"terraform init -migrate-state\".\n"+
2289-
`If you wish to store the current configuration with no changes to the state, use "terraform init -reconfigure".`)

0 commit comments

Comments
 (0)