diff --git a/command/init.go b/command/init.go index 99f0411b1..0febd7271 100644 --- a/command/init.go +++ b/command/init.go @@ -12,6 +12,7 @@ import ( "github.com/posener/complete" "github.com/zclconf/go-cty/cty" + "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform/backend" backendInit "github.com/hashicorp/terraform/backend/init" "github.com/hashicorp/terraform/config" @@ -496,10 +497,15 @@ func (c *InitCommand) getProviders(earlyConfig *earlyconfig.Config, state *state _, err := c.providerInstaller.Get(provider, reqd.Versions) if err != nil { - switch err { - case discovery.ErrorNoSuchProvider: + constraint := reqd.Versions.String() + if constraint == "" { + constraint = "(any version)" + } + + switch { + case err == discovery.ErrorNoSuchProvider: c.Ui.Error(fmt.Sprintf(errProviderNotFound, provider, DefaultPluginVendorDir)) - case discovery.ErrorNoSuitableVersion: + case err == discovery.ErrorNoSuitableVersion: if reqd.Versions.Unconstrained() { // This should never happen, but might crop up if we catch // the releases server in a weird state where the provider's @@ -509,14 +515,21 @@ func (c *InitCommand) getProviders(earlyConfig *earlyconfig.Config, state *state } else { c.Ui.Error(fmt.Sprintf(errProviderVersionsUnsuitable, provider, reqd.Versions)) } - case discovery.ErrorNoVersionCompatible: - // FIXME: This error message is sub-awesome because we don't - // have enough information here to tell the user which versions - // we considered and which versions might be compatible. - constraint := reqd.Versions.String() - if constraint == "" { - constraint = "(any version)" + case errwrap.Contains(err, discovery.ErrorVersionIncompatible.Error()): + // Attempt to fetch nested error to display to the user which versions + // we considered and which versions might be compatible. Otherwise, + // we'll just display a generic version incompatible msg + incompatErr := errwrap.GetType(err, fmt.Errorf("")) + if incompatErr != nil { + c.Ui.Error(incompatErr.Error()) + } else { + // Generic version incompatible msg + c.Ui.Error(fmt.Sprintf(errProviderIncompatible, provider, constraint)) } + // Reset nested errors + err = discovery.ErrorVersionIncompatible + case err == discovery.ErrorNoVersionCompatible: + // Generic version incompatible msg c.Ui.Error(fmt.Sprintf(errProviderIncompatible, provider, constraint)) default: c.Ui.Error(fmt.Sprintf(errProviderInstallError, provider, err.Error(), DefaultPluginVendorDir)) diff --git a/plugin/discovery/error.go b/plugin/discovery/error.go index 0ba58d3d3..6ca8b60aa 100644 --- a/plugin/discovery/error.go +++ b/plugin/discovery/error.go @@ -22,6 +22,11 @@ const ErrorNoSuitableVersion = Error("no suitable version is available") // version of Terraform. const ErrorNoVersionCompatible = Error("no available version is compatible with this version of Terraform") +// ErrorVersionIncompatible indicates that all of the versions within the +// constraints are not compatible with the current version of Terrafrom, though +// there does exist a version outside of the constaints that is compatible. +const ErrorVersionIncompatible = Error("incompatible provider version") + // ErrorNoSuchProvider indicates that no provider exists with a name given const ErrorNoSuchProvider = Error("no provider exists with the given name") diff --git a/plugin/discovery/get.go b/plugin/discovery/get.go index 03d253dd6..d146eb1be 100644 --- a/plugin/discovery/get.go +++ b/plugin/discovery/get.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" + "github.com/hashicorp/errwrap" getter "github.com/hashicorp/go-getter" multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/httpclient" @@ -168,16 +169,22 @@ func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, e } // Prompt version suggestion to UI based on closest protocol match - closestVersion := VersionStr(closestMatch.Version).MustParse() var errMsg string + closestVersion := VersionStr(closestMatch.Version).MustParse() if v.NewerThan(closestVersion) { errMsg = providerProtocolTooNew } else { errMsg = providerProtocolTooOld } - i.Ui.Error(fmt.Sprintf(errMsg, provider, v.String(), tfversion.String(), - closestVersion.String(), closestVersion.MinorUpgradeConstraintStr())) - return PluginMeta{}, ErrorNoVersionCompatible + + constraintStr := req.String() + if constraintStr == "" { + constraintStr = "(any version)" + } + + return PluginMeta{}, errwrap.Wrap(ErrorVersionIncompatible, fmt.Errorf(fmt.Sprintf( + errMsg, provider, v.String(), tfversion.String(), + closestVersion.String(), closestVersion.MinorUpgradeConstraintStr(), constraintStr))) } downloadURLs, err := i.listProviderDownloadURLs(providerSource, versionMeta.Version) @@ -582,27 +589,41 @@ func getFile(url string) ([]byte, error) { return data, nil } -// ProviderProtocolTooOld is a message sent to the CLI UI if the provider's +// providerProtocolTooOld is a message sent to the CLI UI if the provider's // supported protocol versions are too old for the user's version of terraform, // but an older version of the provider is compatible. -const providerProtocolTooOld = `Provider %q v%s is not compatible with Terraform %s. +const providerProtocolTooOld = ` +[reset][bold][red]Provider %q v%s is not compatible with Terraform %s.[reset][red] -Provider version %s is the earliest compatible version. -Select it with the following version constraint: +Provider version %s is the earliest compatible version. Select it with +the following version constraint: - version = %q + version = %q + +Terraform checked all of the plugin versions matching the given constraint: + %s + +Consult the documentation for this provider for more information on +compatibility between provider and Terraform versions. ` -// ProviderProtocolTooNew is a message sent to the CLI UI if the provider's +// providerProtocolTooNew is a message sent to the CLI UI if the provider's // supported protocol versions are too new for the user's version of terraform, // and the user could either upgrade terraform or choose an older version of the // provider -const providerProtocolTooNew = `Provider %q v%s is not compatible with Terraform %s. +const providerProtocolTooNew = ` +[reset][bold][red]Provider %q v%s is not compatible with Terraform %s.[reset][red] -Provider version v%s is the latest compatible version. Select -it with the following constraint: +Provider version %s is the latest compatible version. Select it with +the following constraint: version = %q +Terraform checked all of the plugin versions matching the given constraint: + %s + +Consult the documentation for this provider for more information on +compatibility between provider and Terraform versions. + Alternatively, upgrade to the latest version of Terraform for compatibility with newer provider releases. `