mirror of
https://github.com/hashicorp/terraform.git
synced 2026-06-09 00:42:48 -04:00
init: Fix when error diagnostics are acted on in PSS's experimental version of init. Avoid trying to initialise a state store with insufficient config. (#38125)
Some checks are pending
build / Determine intended Terraform version (push) Waiting to run
build / Determine Go toolchain version (push) Waiting to run
build / Generate release metadata (push) Blocked by required conditions
build / Build for freebsd_386 (push) Blocked by required conditions
build / Build for linux_386 (push) Blocked by required conditions
build / Build for openbsd_386 (push) Blocked by required conditions
build / Build for windows_386 (push) Blocked by required conditions
build / Build for darwin_amd64 (push) Blocked by required conditions
build / Build for freebsd_amd64 (push) Blocked by required conditions
build / Build for linux_amd64 (push) Blocked by required conditions
build / Build for openbsd_amd64 (push) Blocked by required conditions
build / Build for solaris_amd64 (push) Blocked by required conditions
build / Build for windows_amd64 (push) Blocked by required conditions
build / Build for freebsd_arm (push) Blocked by required conditions
build / Build for linux_arm (push) Blocked by required conditions
build / Build for darwin_arm64 (push) Blocked by required conditions
build / Build for linux_arm64 (push) Blocked by required conditions
build / Build for windows_arm64 (push) Blocked by required conditions
build / Build Docker image for linux_386 (push) Blocked by required conditions
build / Build Docker image for linux_amd64 (push) Blocked by required conditions
build / Build Docker image for linux_arm (push) Blocked by required conditions
build / Build Docker image for linux_arm64 (push) Blocked by required conditions
build / Build e2etest for linux_386 (push) Blocked by required conditions
build / Build e2etest for windows_386 (push) Blocked by required conditions
build / Build e2etest for darwin_amd64 (push) Blocked by required conditions
build / Build e2etest for linux_amd64 (push) Blocked by required conditions
build / Build e2etest for windows_amd64 (push) Blocked by required conditions
build / Build e2etest for linux_arm (push) Blocked by required conditions
build / Build e2etest for darwin_arm64 (push) Blocked by required conditions
build / Build e2etest for linux_arm64 (push) Blocked by required conditions
build / Run e2e test for linux_386 (push) Blocked by required conditions
build / Run e2e test for windows_386 (push) Blocked by required conditions
build / Run e2e test for darwin_amd64 (push) Blocked by required conditions
build / Run e2e test for linux_amd64 (push) Blocked by required conditions
build / Run e2e test for windows_amd64 (push) Blocked by required conditions
build / Run e2e test for linux_arm (push) Blocked by required conditions
build / Run e2e test for linux_arm64 (push) Blocked by required conditions
build / Run terraform-exec test for linux amd64 (push) Blocked by required conditions
Quick Checks / Unit Tests (push) Waiting to run
Quick Checks / Race Tests (push) Waiting to run
Quick Checks / End-to-end Tests (push) Waiting to run
Quick Checks / Code Consistency Checks (push) Waiting to run
Some checks are pending
build / Determine intended Terraform version (push) Waiting to run
build / Determine Go toolchain version (push) Waiting to run
build / Generate release metadata (push) Blocked by required conditions
build / Build for freebsd_386 (push) Blocked by required conditions
build / Build for linux_386 (push) Blocked by required conditions
build / Build for openbsd_386 (push) Blocked by required conditions
build / Build for windows_386 (push) Blocked by required conditions
build / Build for darwin_amd64 (push) Blocked by required conditions
build / Build for freebsd_amd64 (push) Blocked by required conditions
build / Build for linux_amd64 (push) Blocked by required conditions
build / Build for openbsd_amd64 (push) Blocked by required conditions
build / Build for solaris_amd64 (push) Blocked by required conditions
build / Build for windows_amd64 (push) Blocked by required conditions
build / Build for freebsd_arm (push) Blocked by required conditions
build / Build for linux_arm (push) Blocked by required conditions
build / Build for darwin_arm64 (push) Blocked by required conditions
build / Build for linux_arm64 (push) Blocked by required conditions
build / Build for windows_arm64 (push) Blocked by required conditions
build / Build Docker image for linux_386 (push) Blocked by required conditions
build / Build Docker image for linux_amd64 (push) Blocked by required conditions
build / Build Docker image for linux_arm (push) Blocked by required conditions
build / Build Docker image for linux_arm64 (push) Blocked by required conditions
build / Build e2etest for linux_386 (push) Blocked by required conditions
build / Build e2etest for windows_386 (push) Blocked by required conditions
build / Build e2etest for darwin_amd64 (push) Blocked by required conditions
build / Build e2etest for linux_amd64 (push) Blocked by required conditions
build / Build e2etest for windows_amd64 (push) Blocked by required conditions
build / Build e2etest for linux_arm (push) Blocked by required conditions
build / Build e2etest for darwin_arm64 (push) Blocked by required conditions
build / Build e2etest for linux_arm64 (push) Blocked by required conditions
build / Run e2e test for linux_386 (push) Blocked by required conditions
build / Run e2e test for windows_386 (push) Blocked by required conditions
build / Run e2e test for darwin_amd64 (push) Blocked by required conditions
build / Run e2e test for linux_amd64 (push) Blocked by required conditions
build / Run e2e test for windows_amd64 (push) Blocked by required conditions
build / Run e2e test for linux_arm (push) Blocked by required conditions
build / Run e2e test for linux_arm64 (push) Blocked by required conditions
build / Run terraform-exec test for linux amd64 (push) Blocked by required conditions
Quick Checks / Unit Tests (push) Waiting to run
Quick Checks / Race Tests (push) Waiting to run
Quick Checks / End-to-end Tests (push) Waiting to run
Quick Checks / Code Consistency Checks (push) Waiting to run
This commit is contained in:
parent
27770ee805
commit
b8c2cabee8
3 changed files with 99 additions and 40 deletions
|
|
@ -167,9 +167,9 @@ func (c *InitCommand) runPssInit(initArgs *arguments.Init, view views.Init) int
|
|||
// With all of the modules (hopefully) installed, we can now try to load the
|
||||
// whole configuration tree.
|
||||
config, confDiags := c.loadConfigWithTests(path, initArgs.TestsDirectory)
|
||||
// configDiags will be handled after the version constraint check, since an
|
||||
// incorrect version of terraform may be producing errors for configuration
|
||||
// constructs added in later versions.
|
||||
// configDiags will be handled after:
|
||||
// - the version constraint check has happened
|
||||
// - and, the backend/state_store is initialised
|
||||
|
||||
// Before we go further, we'll check to make sure none of the modules in
|
||||
// the configuration declare that they don't support this Terraform
|
||||
|
|
@ -181,6 +181,14 @@ func (c *InitCommand) runPssInit(initArgs *arguments.Init, view views.Init) int
|
|||
return 1
|
||||
}
|
||||
|
||||
// We've passed the core version check, now we can show errors from the early configuration.
|
||||
// This prevents trying to initialise the backend with faulty configuration.
|
||||
if earlyConfDiags.HasErrors() {
|
||||
diags = diags.Append(errors.New(view.PrepareMessage(views.InitConfigError)), earlyConfDiags)
|
||||
view.Diagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// Now the full configuration is loaded, we can download the providers specified in the configuration.
|
||||
// This is step one of a two-step provider download process
|
||||
// Providers may be downloaded by this code, but the dependency lock file is only updated later in `init`
|
||||
|
|
@ -226,6 +234,24 @@ func (c *InitCommand) runPssInit(initArgs *arguments.Init, view views.Init) int
|
|||
view.Output(views.EmptyMessage)
|
||||
}
|
||||
|
||||
// Show any errors from initializing the backend.
|
||||
// No preamble using `InitConfigError` is present, as we expect
|
||||
// any errors to from configuring the backend itself.
|
||||
diags = diags.Append(backDiags)
|
||||
if backDiags.HasErrors() {
|
||||
view.Diagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// If everything is ok with the core version check and backend/state_store initialization,
|
||||
// show other errors from loading the full configuration tree.
|
||||
diags = diags.Append(confDiags)
|
||||
if confDiags.HasErrors() {
|
||||
diags = diags.Append(errors.New(view.PrepareMessage(views.InitConfigError)))
|
||||
view.Diagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
var state *states.State
|
||||
|
||||
// If we have a functional backend (either just initialized or initialized
|
||||
|
|
@ -288,33 +314,6 @@ func (c *InitCommand) runPssInit(initArgs *arguments.Init, view views.Init) int
|
|||
view.Output(views.EmptyMessage)
|
||||
}
|
||||
|
||||
// As Terraform version-related diagnostics are handled above, we can now
|
||||
// check the diagnostics from the early configuration and the backend.
|
||||
diags = diags.Append(earlyConfDiags)
|
||||
diags = diags.Append(backDiags)
|
||||
if earlyConfDiags.HasErrors() {
|
||||
diags = diags.Append(errors.New(view.PrepareMessage(views.InitConfigError)))
|
||||
view.Diagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// Now, we can show any errors from initializing the backend, but we won't
|
||||
// show the InitConfigError preamble as we didn't detect problems with
|
||||
// the early configuration.
|
||||
if backDiags.HasErrors() {
|
||||
view.Diagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
// If everything is ok with the core version check and backend initialization,
|
||||
// show other errors from loading the full configuration tree.
|
||||
diags = diags.Append(confDiags)
|
||||
if confDiags.HasErrors() {
|
||||
diags = diags.Append(errors.New(view.PrepareMessage(views.InitConfigError)))
|
||||
view.Diagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
|
||||
if cb, ok := back.(*cloud.Cloud); ok {
|
||||
if c.RunningInAutomation {
|
||||
if err := cb.AssertImportCompatible(config); err != nil {
|
||||
|
|
@ -522,7 +521,6 @@ However, if you intended to override a defined backend, please verify that
|
|||
the backend configuration is present and valid.
|
||||
`,
|
||||
))
|
||||
|
||||
}
|
||||
|
||||
opts = &BackendOpts{
|
||||
|
|
|
|||
|
|
@ -4707,7 +4707,7 @@ func TestInit_stateStore_to_backend(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestInit_unitialized_stateStore(t *testing.T) {
|
||||
func TestInit_uninitialized_stateStore(t *testing.T) {
|
||||
// Create a temporary working directory that is empty
|
||||
td := t.TempDir()
|
||||
cfg := `terraform {
|
||||
|
|
@ -5641,6 +5641,65 @@ func TestInit_cloud_to_stateStore(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test that config-parsing errors that prevent initialising the pluggable state store are identified and returned
|
||||
// before Terraform attempts to initialise the store.
|
||||
//
|
||||
// These errors include omitting the necessary entry in required_providers, or causing an issue with how require_providers
|
||||
// is parsed. This test uses the first scenario for simplicity.
|
||||
func TestInit_configErrorsImpactingStateStore(t *testing.T) {
|
||||
td := t.TempDir()
|
||||
t.Chdir(td)
|
||||
cfg1 := `terraform {
|
||||
required_providers {
|
||||
foobar = {
|
||||
source = "hashicorp/foobar"
|
||||
}
|
||||
}
|
||||
state_store "test_store" {
|
||||
provider "test" {} # missing from required_providers
|
||||
value = "foobar"
|
||||
}
|
||||
}
|
||||
`
|
||||
if err := os.WriteFile(filepath.Join(td, "main.tf"), []byte(cfg1), 0644); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, done := testView(t)
|
||||
initCmd := &InitCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
AllowExperimentalFeatures: true,
|
||||
},
|
||||
}
|
||||
|
||||
log.Printf("[TRACE] TestInit_configErrorsImpactingStateStore: init start")
|
||||
args := []string{"-enable-pluggable-state-storage-experiment"}
|
||||
code := initCmd.Run(args)
|
||||
testOutput := done(t)
|
||||
if code != 1 {
|
||||
t.Fatalf("expected apply to fail with code 1, got code %d: \n%s", code, testOutput.All())
|
||||
}
|
||||
log.Printf("[TRACE] TestInit_configErrorsImpactingStateStore: init complete")
|
||||
t.Logf("init output:\n%s", testOutput.Stdout())
|
||||
t.Logf("init errors:\n%s", testOutput.Stderr())
|
||||
|
||||
expectedErrs := []string{
|
||||
// Pre-amble text that's shown when a config-parsing error occurs during init.
|
||||
"Error: Terraform encountered problems during initialisation, including problems with the configuration, described below.",
|
||||
// This parsing error previously wouldn't be reported before initialising the backend, so
|
||||
// Terraform attempted to use a state store in the missing provider.
|
||||
"Error: Missing entry in required_providers",
|
||||
}
|
||||
for _, e := range expectedErrs {
|
||||
if !strings.Contains(cleanString(testOutput.Stderr()), e) {
|
||||
t.Fatalf("unexpected error, expected %q, given: %s", e, testOutput.Stderr())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// newMockProviderSource is a helper to succinctly construct a mock provider
|
||||
// source that contains a set of packages matching the given provider versions
|
||||
// that are available for installation (from temporary local files).
|
||||
|
|
|
|||
|
|
@ -120,14 +120,16 @@ func resolveStateStoreProviderType(requiredProviders map[string]*RequiredProvide
|
|||
// that the builtin provider is intended.
|
||||
return addrs.NewBuiltInProvider("terraform"), nil
|
||||
case !foundReqProviderEntry:
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing entry in required_providers",
|
||||
Detail: fmt.Sprintf("The provider used for state storage must have a matching entry in required_providers. Please add an entry for provider %s",
|
||||
stateStore.Provider.Name,
|
||||
),
|
||||
Subject: &stateStore.DeclRange,
|
||||
})
|
||||
diags = diags.Append(
|
||||
&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing entry in required_providers",
|
||||
Detail: fmt.Sprintf("The provider used for state storage must have a matching entry in required_providers. Please add an entry for provider %s",
|
||||
stateStore.Provider.Name,
|
||||
),
|
||||
Subject: &stateStore.DeclRange,
|
||||
},
|
||||
)
|
||||
return tfaddr.Provider{}, diags
|
||||
default:
|
||||
// We've got a required_providers entry to use
|
||||
|
|
|
|||
Loading…
Reference in a new issue