From 6cc3e1d0bd635cdae92b3e0055c19d86dfa7a222 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 20 Feb 2019 14:18:37 -0500 Subject: [PATCH 1/2] 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. --- backend/local/backend.go | 23 ----------------------- terraform/context.go | 10 ++++++---- terraform/resource_provider.go | 30 +++++++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/backend/local/backend.go b/backend/local/backend.go index eb2053b23..8a4050362 100644 --- a/backend/local/backend.go +++ b/backend/local/backend.go @@ -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". -` diff --git a/terraform/context.go b/terraform/context.go index 14e3863a6..afdba99c1 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -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 { diff --git a/terraform/resource_provider.go b/terraform/resource_provider.go index e666fb6d2..17f93e10d 100644 --- a/terraform/resource_provider.go +++ b/terraform/resource_provider.go @@ -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". +` From 44afe5b6ff12c74a6731bd40b5bbab5e85c2d35e Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 20 Feb 2019 14:23:56 -0500 Subject: [PATCH 2/2] remove unused ResourceProviderError --- terraform/resource_provider.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/terraform/resource_provider.go b/terraform/resource_provider.go index 17f93e10d..3455ad88c 100644 --- a/terraform/resource_provider.go +++ b/terraform/resource_provider.go @@ -5,7 +5,6 @@ import ( "github.com/hashicorp/terraform/tfdiags" - multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/plugin/discovery" "github.com/hashicorp/terraform/providers" ) @@ -172,18 +171,6 @@ type ResourceProvider interface { ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error) } -// ResourceProviderError may be returned when creating a Context if the -// required providers cannot be satisfied. This error can then be used to -// format a more useful message for the user. -type ResourceProviderError struct { - Errors []error -} - -func (e *ResourceProviderError) Error() string { - // use multierror to format the default output - return multierror.Append(nil, e.Errors...).Error() -} - // ResourceProviderCloser is an interface that providers that can close // connections that aren't needed anymore must implement. type ResourceProviderCloser interface {