move init error to where it is generated

The init error was output deep in the backend by detecting a
special ResourceProviderError and formatted directly to the CLI.

Create some Diagnostics closer to where the problem is detected, and
passed that back through the normal diagnostic flow. While the output
isn't as nice yet, this restores the helpful error message and makes the
code easier to maintain. Better formatting can be handled later.
This commit is contained in:
James Bardin 2019-02-20 14:18:37 -05:00
parent 626022670e
commit 6cc3e1d0bd
3 changed files with 33 additions and 30 deletions

View File

@ -9,7 +9,6 @@ import (
"os"
"path/filepath"
"sort"
"strings"
"sync"
"github.com/hashicorp/terraform/backend"
@ -594,25 +593,3 @@ func (b *Local) stateWorkspaceDir() string {
return DefaultWorkspaceDir
}
func (b *Local) pluginInitRequired(providerErr *terraform.ResourceProviderError) {
b.CLI.Output(b.Colorize().Color(fmt.Sprintf(
strings.TrimSpace(errPluginInit)+"\n",
providerErr)))
}
// this relies on multierror to format the plugin errors below the copy
const errPluginInit = `
[reset][bold][yellow]Plugin reinitialization required. Please run "terraform init".[reset]
[yellow]Reason: Could not satisfy plugin requirements.
Plugins are external binaries that Terraform uses to access and manipulate
resources. The configuration provided requires plugins which can't be located,
don't satisfy the version constraints, or are otherwise incompatible.
[reset][red]%s
[reset][yellow]Terraform automatically discovers provider requirements from your
configuration, including providers used in child modules. To see the
requirements and constraints from each module, run "terraform providers".
`

View File

@ -172,16 +172,18 @@ func NewContext(opts *ContextOpts) (*Context, tfdiags.Diagnostics) {
// Bind available provider plugins to the constraints in config
var providerFactories map[string]providers.Factory
if opts.ProviderResolver != nil {
var err error
deps := ConfigTreeDependencies(opts.Config, state)
reqd := deps.AllPluginRequirements()
if opts.ProviderSHA256s != nil && !opts.SkipProviderVerify {
reqd.LockExecutables(opts.ProviderSHA256s)
}
log.Printf("[TRACE] terraform.NewContext: resolving provider version selections")
providerFactories, err = resourceProviderFactories(opts.ProviderResolver, reqd)
if err != nil {
diags = diags.Append(err)
var providerDiags tfdiags.Diagnostics
providerFactories, providerDiags = resourceProviderFactories(opts.ProviderResolver, reqd)
diags = diags.Append(providerDiags)
if diags.HasErrors() {
return nil, diags
}
} else {

View File

@ -3,6 +3,8 @@ package terraform
import (
"fmt"
"github.com/hashicorp/terraform/tfdiags"
multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform/plugin/discovery"
"github.com/hashicorp/terraform/providers"
@ -296,13 +298,35 @@ func ProviderHasDataSource(p ResourceProvider, n string) bool {
// This should be called only with configurations that have passed calls
// to config.Validate(), which ensures that all of the given version
// constraints are valid. It will panic if any invalid constraints are present.
func resourceProviderFactories(resolver providers.Resolver, reqd discovery.PluginRequirements) (map[string]providers.Factory, error) {
func resourceProviderFactories(resolver providers.Resolver, reqd discovery.PluginRequirements) (map[string]providers.Factory, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
ret, errs := resolver.ResolveProviders(reqd)
if errs != nil {
return nil, &ResourceProviderError{
Errors: errs,
diags = diags.Append(
tfdiags.Sourceless(tfdiags.Error,
"Could not satisfy plugin requirements",
errPluginInit,
),
)
for _, err := range errs {
diags = diags.Append(err)
}
return nil, diags
}
return ret, nil
}
const errPluginInit = `
Plugin reinitialization required. Please run "terraform init".
Plugins are external binaries that Terraform uses to access and manipulate
resources. The configuration provided requires plugins which can't be located,
don't satisfy the version constraints, or are otherwise incompatible.
Terraform automatically discovers provider requirements from your
configuration, including providers used in child modules. To see the
requirements and constraints from each module, run "terraform providers".
`