Merge pull request #29792 from hashicorp/alisdair/init-missing-cache
cli: Fix init failure with deleted cache
This commit is contained in:
commit
92a9aa9b39
|
@ -57,7 +57,7 @@ func TestProviderTampering(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, stderr, err := tf.Run("plan")
|
stdout, stderr, err := tf.Run("plan")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("unexpected plan success\nstdout:\n%s", stdout)
|
t.Fatalf("unexpected plan success\nstdout:\n%s", stdout)
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,16 @@ func TestProviderTampering(t *testing.T) {
|
||||||
if want := `terraform init`; !strings.Contains(stderr, want) {
|
if want := `terraform init`; !strings.Contains(stderr, want) {
|
||||||
t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
|
t.Errorf("missing expected error message\nwant substring: %s\ngot:\n%s", want, stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Running init as suggested resolves the problem
|
||||||
|
_, stderr, err = tf.Run("init")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected init error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
|
_, stderr, err = tf.Run("plan")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected plan error: %s\nstderr:\n%s", err, stderr)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
t.Run("null plugin package modified before plan", func(t *testing.T) {
|
t.Run("null plugin package modified before plan", func(t *testing.T) {
|
||||||
tf := e2e.NewBinary(terraformBin, seedDir)
|
tf := e2e.NewBinary(terraformBin, seedDir)
|
||||||
|
|
|
@ -238,7 +238,7 @@ func (c *InitCommand) Run(args []string) int {
|
||||||
// by a previous run, so we must still expect that "back" may be nil
|
// by a previous run, so we must still expect that "back" may be nil
|
||||||
// in code that follows.
|
// in code that follows.
|
||||||
var backDiags tfdiags.Diagnostics
|
var backDiags tfdiags.Diagnostics
|
||||||
back, backDiags = c.Backend(nil)
|
back, backDiags = c.Backend(&BackendOpts{Init: true})
|
||||||
if backDiags.HasErrors() {
|
if backDiags.HasErrors() {
|
||||||
// This is fine. We'll proceed with no backend, then.
|
// This is fine. We'll proceed with no backend, then.
|
||||||
back = nil
|
back = nil
|
||||||
|
|
|
@ -459,10 +459,8 @@ func (m *Meta) contextOpts() (*terraform.ContextOpts, error) {
|
||||||
opts.Providers = m.testingOverrides.Providers
|
opts.Providers = m.testingOverrides.Providers
|
||||||
opts.Provisioners = m.testingOverrides.Provisioners
|
opts.Provisioners = m.testingOverrides.Provisioners
|
||||||
} else {
|
} else {
|
||||||
providerFactories, err := m.providerFactories()
|
var providerFactories map[addrs.Provider]providers.Factory
|
||||||
if err != nil {
|
providerFactories, err = m.providerFactories()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
opts.Providers = providerFactories
|
opts.Providers = providerFactories
|
||||||
opts.Provisioners = m.provisionerFactories()
|
opts.Provisioners = m.provisionerFactories()
|
||||||
}
|
}
|
||||||
|
@ -472,7 +470,7 @@ func (m *Meta) contextOpts() (*terraform.ContextOpts, error) {
|
||||||
OriginalWorkingDir: m.WorkingDir.OriginalWorkingDir(),
|
OriginalWorkingDir: m.WorkingDir.OriginalWorkingDir(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &opts, nil
|
return &opts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultFlagSet creates a default flag set for commands.
|
// defaultFlagSet creates a default flag set for commands.
|
||||||
|
|
|
@ -112,28 +112,34 @@ func (m *Meta) Backend(opts *BackendOpts) (backend.Enhanced, tfdiags.Diagnostics
|
||||||
// indicates one or more inconsistencies between the dependency
|
// indicates one or more inconsistencies between the dependency
|
||||||
// lock file and the provider plugins actually available in the
|
// lock file and the provider plugins actually available in the
|
||||||
// local cache directory.
|
// local cache directory.
|
||||||
var buf bytes.Buffer
|
//
|
||||||
for addr, err := range errs {
|
// If initialization is allowed, we ignore this error, as it may
|
||||||
fmt.Fprintf(&buf, "\n - %s: %s", addr, err)
|
// be resolved by the later step where providers are fetched.
|
||||||
|
if !opts.Init {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for addr, err := range errs {
|
||||||
|
fmt.Fprintf(&buf, "\n - %s: %s", addr, err)
|
||||||
|
}
|
||||||
|
suggestion := "To download the plugins required for this configuration, run:\n terraform init"
|
||||||
|
if m.RunningInAutomation {
|
||||||
|
// Don't mention "terraform init" specifically if we're running in an automation wrapper
|
||||||
|
suggestion = "You must install the required plugins before running Terraform operations."
|
||||||
|
}
|
||||||
|
diags = diags.Append(tfdiags.Sourceless(
|
||||||
|
tfdiags.Error,
|
||||||
|
"Required plugins are not installed",
|
||||||
|
fmt.Sprintf(
|
||||||
|
"The installed provider plugins are not consistent with the packages selected in the dependency lock file:%s\n\nTerraform uses external plugins to integrate with a variety of different infrastructure services. %s",
|
||||||
|
buf.String(), suggestion,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
return nil, diags
|
||||||
}
|
}
|
||||||
suggestion := "To download the plugins required for this configuration, run:\n terraform init"
|
|
||||||
if m.RunningInAutomation {
|
|
||||||
// Don't mention "terraform init" specifically if we're running in an automation wrapper
|
|
||||||
suggestion = "You must install the required plugins before running Terraform operations."
|
|
||||||
}
|
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
|
||||||
tfdiags.Error,
|
|
||||||
"Required plugins are not installed",
|
|
||||||
fmt.Sprintf(
|
|
||||||
"The installed provider plugins are not consistent with the packages selected in the dependency lock file:%s\n\nTerraform uses external plugins to integrate with a variety of different infrastructure services. %s",
|
|
||||||
buf.String(), suggestion,
|
|
||||||
),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
// All other errors just get generic handling.
|
// All other errors just get generic handling.
|
||||||
diags = diags.Append(err)
|
diags = diags.Append(err)
|
||||||
|
return nil, diags
|
||||||
}
|
}
|
||||||
return nil, diags
|
|
||||||
}
|
}
|
||||||
cliOpts.Validation = true
|
cliOpts.Validation = true
|
||||||
|
|
||||||
|
@ -337,7 +343,7 @@ func (m *Meta) BackendForPlan(settings plans.Backend) (backend.Enhanced, tfdiags
|
||||||
// a backend that supports local CLI operations.
|
// a backend that supports local CLI operations.
|
||||||
func (m *Meta) backendCLIOpts() (*backend.CLIOpts, error) {
|
func (m *Meta) backendCLIOpts() (*backend.CLIOpts, error) {
|
||||||
contextOpts, err := m.contextOpts()
|
contextOpts, err := m.contextOpts()
|
||||||
if err != nil {
|
if contextOpts == nil && err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &backend.CLIOpts{
|
return &backend.CLIOpts{
|
||||||
|
@ -350,7 +356,7 @@ func (m *Meta) backendCLIOpts() (*backend.CLIOpts, error) {
|
||||||
ContextOpts: contextOpts,
|
ContextOpts: contextOpts,
|
||||||
Input: m.Input(),
|
Input: m.Input(),
|
||||||
RunningInAutomation: m.RunningInAutomation,
|
RunningInAutomation: m.RunningInAutomation,
|
||||||
}, nil
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operation initializes a new backend.Operation struct.
|
// Operation initializes a new backend.Operation struct.
|
||||||
|
|
Loading…
Reference in New Issue