github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/command/init.go (about)

     1  package command
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/hcl/v2"
    10  	"github.com/hashicorp/terraform-config-inspect/tfconfig"
    11  	svchost "github.com/hashicorp/terraform-svchost"
    12  	"github.com/posener/complete"
    13  	"github.com/zclconf/go-cty/cty"
    14  
    15  	"github.com/muratcelep/terraform/not-internal/addrs"
    16  	"github.com/muratcelep/terraform/not-internal/backend"
    17  	backendInit "github.com/muratcelep/terraform/not-internal/backend/init"
    18  	"github.com/muratcelep/terraform/not-internal/cloud"
    19  	"github.com/muratcelep/terraform/not-internal/configs"
    20  	"github.com/muratcelep/terraform/not-internal/configs/configschema"
    21  	"github.com/muratcelep/terraform/not-internal/getproviders"
    22  	"github.com/muratcelep/terraform/not-internal/providercache"
    23  	"github.com/muratcelep/terraform/not-internal/states"
    24  	"github.com/muratcelep/terraform/not-internal/terraform"
    25  	"github.com/muratcelep/terraform/not-internal/tfdiags"
    26  	tfversion "github.com/muratcelep/terraform/version"
    27  )
    28  
    29  // InitCommand is a Command implementation that takes a Terraform
    30  // module and clones it to the working directory.
    31  type InitCommand struct {
    32  	Meta
    33  }
    34  
    35  func (c *InitCommand) Run(args []string) int {
    36  	var flagFromModule, flagLockfile string
    37  	var flagBackend, flagGet, flagUpgrade bool
    38  	var flagPluginPath FlagStringSlice
    39  	flagConfigExtra := newRawFlags("-backend-config")
    40  
    41  	args = c.Meta.process(args)
    42  	cmdFlags := c.Meta.extendedFlagSet("init")
    43  	cmdFlags.BoolVar(&flagBackend, "backend", true, "")
    44  	cmdFlags.Var(flagConfigExtra, "backend-config", "")
    45  	cmdFlags.StringVar(&flagFromModule, "from-module", "", "copy the source of the given module into the directory before init")
    46  	cmdFlags.BoolVar(&flagGet, "get", true, "")
    47  	cmdFlags.BoolVar(&c.forceInitCopy, "force-copy", false, "suppress prompts about copying state data")
    48  	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
    49  	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
    50  	cmdFlags.BoolVar(&c.reconfigure, "reconfigure", false, "reconfigure")
    51  	cmdFlags.BoolVar(&c.migrateState, "migrate-state", false, "migrate state")
    52  	cmdFlags.BoolVar(&flagUpgrade, "upgrade", false, "")
    53  	cmdFlags.Var(&flagPluginPath, "plugin-dir", "plugin directory")
    54  	cmdFlags.StringVar(&flagLockfile, "lockfile", "", "Set a dependency lockfile mode")
    55  	cmdFlags.BoolVar(&c.Meta.ignoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible")
    56  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    57  	if err := cmdFlags.Parse(args); err != nil {
    58  		return 1
    59  	}
    60  
    61  	if c.migrateState && c.reconfigure {
    62  		c.Ui.Error("The -migrate-state and -reconfigure options are mutually-exclusive")
    63  		return 1
    64  	}
    65  
    66  	// Copying the state only happens during backend migration, so setting
    67  	// -force-copy implies -migrate-state
    68  	if c.forceInitCopy {
    69  		c.migrateState = true
    70  	}
    71  
    72  	var diags tfdiags.Diagnostics
    73  
    74  	if len(flagPluginPath) > 0 {
    75  		c.pluginPath = flagPluginPath
    76  	}
    77  
    78  	// Validate the arg count and get the working directory
    79  	args = cmdFlags.Args()
    80  	path, err := ModulePath(args)
    81  	if err != nil {
    82  		c.Ui.Error(err.Error())
    83  		return 1
    84  	}
    85  
    86  	if err := c.storePluginPath(c.pluginPath); err != nil {
    87  		c.Ui.Error(fmt.Sprintf("Error saving -plugin-path values: %s", err))
    88  		return 1
    89  	}
    90  
    91  	// This will track whether we outputted anything so that we know whether
    92  	// to output a newline before the success message
    93  	var header bool
    94  
    95  	if flagFromModule != "" {
    96  		src := flagFromModule
    97  
    98  		empty, err := configs.IsEmptyDir(path)
    99  		if err != nil {
   100  			c.Ui.Error(fmt.Sprintf("Error validating destination directory: %s", err))
   101  			return 1
   102  		}
   103  		if !empty {
   104  			c.Ui.Error(strings.TrimSpace(errInitCopyNotEmpty))
   105  			return 1
   106  		}
   107  
   108  		c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
   109  			"[reset][bold]Copying configuration[reset] from %q...", src,
   110  		)))
   111  		header = true
   112  
   113  		hooks := uiModuleInstallHooks{
   114  			Ui:             c.Ui,
   115  			ShowLocalPaths: false, // since they are in a weird location for init
   116  		}
   117  
   118  		initDirFromModuleAbort, initDirFromModuleDiags := c.initDirFromModule(path, src, hooks)
   119  		diags = diags.Append(initDirFromModuleDiags)
   120  		if initDirFromModuleAbort || initDirFromModuleDiags.HasErrors() {
   121  			c.showDiagnostics(diags)
   122  			return 1
   123  		}
   124  
   125  		c.Ui.Output("")
   126  	}
   127  
   128  	// If our directory is empty, then we're done. We can't get or set up
   129  	// the backend with an empty directory.
   130  	empty, err := configs.IsEmptyDir(path)
   131  	if err != nil {
   132  		diags = diags.Append(fmt.Errorf("Error checking configuration: %s", err))
   133  		c.showDiagnostics(diags)
   134  		return 1
   135  	}
   136  	if empty {
   137  		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitEmpty)))
   138  		return 0
   139  	}
   140  
   141  	// For Terraform v0.12 we introduced a special loading mode where we would
   142  	// use the 0.11-syntax-compatible "earlyconfig" package as a heuristic to
   143  	// identify situations where it was likely that the user was trying to use
   144  	// 0.11-only syntax that the upgrade tool might help with.
   145  	//
   146  	// However, as the language has moved on that is no longer a suitable
   147  	// heuristic in Terraform 0.13 and later: other new additions to the
   148  	// language can cause the main loader to disagree with earlyconfig, which
   149  	// would lead us to give poor advice about how to respond.
   150  	//
   151  	// For that reason, we no longer use a different error message in that
   152  	// situation, but for now we still use both codepaths because some of our
   153  	// initialization functionality remains built around "earlyconfig" and
   154  	// so we need to still load the module via that mechanism anyway until we
   155  	// can do some more invasive refactoring here.
   156  	rootModEarly, earlyConfDiags := c.loadSingleModuleEarly(path)
   157  	// If _only_ the early loader encountered errors then that's unusual
   158  	// (it should generally be a superset of the normal loader) but we'll
   159  	// return those errors anyway since otherwise we'll probably get
   160  	// some weird behavior downstream. Errors from the early loader are
   161  	// generally not as high-quality since it has less context to work with.
   162  	if earlyConfDiags.HasErrors() {
   163  		c.Ui.Error(c.Colorize().Color(strings.TrimSpace(errInitConfigError)))
   164  		// Errors from the early loader are generally not as high-quality since
   165  		// it has less context to work with.
   166  
   167  		// TODO: It would be nice to check the version constraints in
   168  		// rootModEarly.RequiredCore and print out a hint if the module is
   169  		// declaring that it's not compatible with this version of Terraform,
   170  		// and that may be what caused earlyconfig to fail.
   171  		diags = diags.Append(earlyConfDiags)
   172  		c.showDiagnostics(diags)
   173  		return 1
   174  	}
   175  
   176  	if flagGet {
   177  		modsOutput, modsAbort, modsDiags := c.getModules(path, rootModEarly, flagUpgrade)
   178  		diags = diags.Append(modsDiags)
   179  		if modsAbort || modsDiags.HasErrors() {
   180  			c.showDiagnostics(diags)
   181  			return 1
   182  		}
   183  		if modsOutput {
   184  			header = true
   185  		}
   186  	}
   187  
   188  	// With all of the modules (hopefully) installed, we can now try to load the
   189  	// whole configuration tree.
   190  	config, confDiags := c.loadConfig(path)
   191  	// configDiags will be handled after the version constraint check, since an
   192  	// incorrect version of terraform may be producing errors for configuration
   193  	// constructs added in later versions.
   194  
   195  	// Before we go further, we'll check to make sure none of the modules in
   196  	// the configuration declare that they don't support this Terraform
   197  	// version, so we can produce a version-related error message rather than
   198  	// potentially-confusing downstream errors.
   199  	versionDiags := terraform.CheckCoreVersionRequirements(config)
   200  	if versionDiags.HasErrors() {
   201  		c.showDiagnostics(versionDiags)
   202  		return 1
   203  	}
   204  
   205  	diags = diags.Append(confDiags)
   206  	if confDiags.HasErrors() {
   207  		c.Ui.Error(strings.TrimSpace(errInitConfigError))
   208  		c.showDiagnostics(diags)
   209  		return 1
   210  	}
   211  
   212  	var back backend.Backend
   213  
   214  	switch {
   215  	case config.Module.CloudConfig != nil:
   216  		be, backendOutput, backendDiags := c.initCloud(config.Module, flagConfigExtra)
   217  		diags = diags.Append(backendDiags)
   218  		if backendDiags.HasErrors() {
   219  			c.showDiagnostics(diags)
   220  			return 1
   221  		}
   222  		if backendOutput {
   223  			header = true
   224  		}
   225  		back = be
   226  	case flagBackend:
   227  		be, backendOutput, backendDiags := c.initBackend(config.Module, flagConfigExtra)
   228  		diags = diags.Append(backendDiags)
   229  		if backendDiags.HasErrors() {
   230  			c.showDiagnostics(diags)
   231  			return 1
   232  		}
   233  		if backendOutput {
   234  			header = true
   235  		}
   236  		back = be
   237  	default:
   238  		// load the previously-stored backend config
   239  		be, backendDiags := c.Meta.backendFromState()
   240  		diags = diags.Append(backendDiags)
   241  		if backendDiags.HasErrors() {
   242  			c.showDiagnostics(diags)
   243  			return 1
   244  		}
   245  		back = be
   246  	}
   247  
   248  	if back == nil {
   249  		// If we didn't initialize a backend then we'll try to at least
   250  		// instantiate one. This might fail if it wasn't already initialized
   251  		// by a previous run, so we must still expect that "back" may be nil
   252  		// in code that follows.
   253  		var backDiags tfdiags.Diagnostics
   254  		back, backDiags = c.Backend(&BackendOpts{Init: true})
   255  		if backDiags.HasErrors() {
   256  			// This is fine. We'll proceed with no backend, then.
   257  			back = nil
   258  		}
   259  	}
   260  
   261  	var state *states.State
   262  
   263  	// If we have a functional backend (either just initialized or initialized
   264  	// on a previous run) we'll use the current state as a potential source
   265  	// of provider dependencies.
   266  	if back != nil {
   267  		c.ignoreRemoteVersionConflict(back)
   268  		workspace, err := c.Workspace()
   269  		if err != nil {
   270  			c.Ui.Error(fmt.Sprintf("Error selecting workspace: %s", err))
   271  			return 1
   272  		}
   273  		sMgr, err := back.StateMgr(workspace)
   274  		if err != nil {
   275  			c.Ui.Error(fmt.Sprintf("Error loading state: %s", err))
   276  			return 1
   277  		}
   278  
   279  		if err := sMgr.RefreshState(); err != nil {
   280  			c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
   281  			return 1
   282  		}
   283  
   284  		state = sMgr.State()
   285  	}
   286  
   287  	// Now that we have loaded all modules, check the module tree for missing providers.
   288  	providersOutput, providersAbort, providerDiags := c.getProviders(config, state, flagUpgrade, flagPluginPath, flagLockfile)
   289  	diags = diags.Append(providerDiags)
   290  	if providersAbort || providerDiags.HasErrors() {
   291  		c.showDiagnostics(diags)
   292  		return 1
   293  	}
   294  	if providersOutput {
   295  		header = true
   296  	}
   297  
   298  	// If we outputted information, then we need to output a newline
   299  	// so that our success message is nicely spaced out from prior text.
   300  	if header {
   301  		c.Ui.Output("")
   302  	}
   303  
   304  	// If we accumulated any warnings along the way that weren't accompanied
   305  	// by errors then we'll output them here so that the success message is
   306  	// still the final thing shown.
   307  	c.showDiagnostics(diags)
   308  	_, cloud := back.(*cloud.Cloud)
   309  	output := outputInitSuccess
   310  	if cloud {
   311  		output = outputInitSuccessCloud
   312  	}
   313  
   314  	c.Ui.Output(c.Colorize().Color(strings.TrimSpace(output)))
   315  
   316  	if !c.RunningInAutomation {
   317  		// If we're not running in an automation wrapper, give the user
   318  		// some more detailed next steps that are appropriate for interactive
   319  		// shell usage.
   320  		output = outputInitSuccessCLI
   321  		if cloud {
   322  			output = outputInitSuccessCLICloud
   323  		}
   324  		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(output)))
   325  	}
   326  	return 0
   327  }
   328  
   329  func (c *InitCommand) getModules(path string, earlyRoot *tfconfig.Module, upgrade bool) (output bool, abort bool, diags tfdiags.Diagnostics) {
   330  	if len(earlyRoot.ModuleCalls) == 0 {
   331  		// Nothing to do
   332  		return false, false, nil
   333  	}
   334  
   335  	if upgrade {
   336  		c.Ui.Output(c.Colorize().Color("[reset][bold]Upgrading modules..."))
   337  	} else {
   338  		c.Ui.Output(c.Colorize().Color("[reset][bold]Initializing modules..."))
   339  	}
   340  
   341  	hooks := uiModuleInstallHooks{
   342  		Ui:             c.Ui,
   343  		ShowLocalPaths: true,
   344  	}
   345  
   346  	installAbort, installDiags := c.installModules(path, upgrade, hooks)
   347  	diags = diags.Append(installDiags)
   348  
   349  	// At this point, installModules may have generated error diags or been
   350  	// aborted by SIGINT. In any case we continue and the manifest as best
   351  	// we can.
   352  
   353  	// Since module installer has modified the module manifest on disk, we need
   354  	// to refresh the cache of it in the loader.
   355  	if c.configLoader != nil {
   356  		if err := c.configLoader.RefreshModules(); err != nil {
   357  			// Should never happen
   358  			diags = diags.Append(tfdiags.Sourceless(
   359  				tfdiags.Error,
   360  				"Failed to read module manifest",
   361  				fmt.Sprintf("After installing modules, Terraform could not re-read the manifest of installed modules. This is a bug in Terraform. %s.", err),
   362  			))
   363  		}
   364  	}
   365  
   366  	return true, installAbort, diags
   367  }
   368  
   369  func (c *InitCommand) initCloud(root *configs.Module, extraConfig rawFlags) (be backend.Backend, output bool, diags tfdiags.Diagnostics) {
   370  	c.Ui.Output(c.Colorize().Color("\n[reset][bold]Initializing Terraform Cloud..."))
   371  
   372  	if len(extraConfig.AllItems()) != 0 {
   373  		diags = diags.Append(tfdiags.Sourceless(
   374  			tfdiags.Error,
   375  			"Invalid command-line option",
   376  			"The -backend-config=... command line option is only for state backends, and is not applicable to Terraform Cloud-based configurations.\n\nTo change the set of workspaces associated with this configuration, edit the Cloud configuration block in the root module.",
   377  		))
   378  		return nil, true, diags
   379  	}
   380  
   381  	backendConfig := root.CloudConfig.ToBackendConfig()
   382  
   383  	opts := &BackendOpts{
   384  		Config: &backendConfig,
   385  		Init:   true,
   386  	}
   387  
   388  	back, backDiags := c.Backend(opts)
   389  	diags = diags.Append(backDiags)
   390  	return back, true, diags
   391  }
   392  
   393  func (c *InitCommand) initBackend(root *configs.Module, extraConfig rawFlags) (be backend.Backend, output bool, diags tfdiags.Diagnostics) {
   394  	c.Ui.Output(c.Colorize().Color("\n[reset][bold]Initializing the backend..."))
   395  
   396  	var backendConfig *configs.Backend
   397  	var backendConfigOverride hcl.Body
   398  	if root.Backend != nil {
   399  		backendType := root.Backend.Type
   400  		if backendType == "cloud" {
   401  			diags = diags.Append(&hcl.Diagnostic{
   402  				Severity: hcl.DiagError,
   403  				Summary:  "Unsupported backend type",
   404  				Detail:   fmt.Sprintf("There is no explicit backend type named %q. To configure Terraform Cloud, declare a 'cloud' block instead.", backendType),
   405  				Subject:  &root.Backend.TypeRange,
   406  			})
   407  			return nil, true, diags
   408  		}
   409  
   410  		bf := backendInit.Backend(backendType)
   411  		if bf == nil {
   412  			diags = diags.Append(&hcl.Diagnostic{
   413  				Severity: hcl.DiagError,
   414  				Summary:  "Unsupported backend type",
   415  				Detail:   fmt.Sprintf("There is no backend type named %q.", backendType),
   416  				Subject:  &root.Backend.TypeRange,
   417  			})
   418  			return nil, true, diags
   419  		}
   420  
   421  		b := bf()
   422  		backendSchema := b.ConfigSchema()
   423  		backendConfig = root.Backend
   424  
   425  		var overrideDiags tfdiags.Diagnostics
   426  		backendConfigOverride, overrideDiags = c.backendConfigOverrideBody(extraConfig, backendSchema)
   427  		diags = diags.Append(overrideDiags)
   428  		if overrideDiags.HasErrors() {
   429  			return nil, true, diags
   430  		}
   431  	} else {
   432  		// If the user supplied a -backend-config on the CLI but no backend
   433  		// block was found in the configuration, it's likely - but not
   434  		// necessarily - a mistake. Return a warning.
   435  		if !extraConfig.Empty() {
   436  			diags = diags.Append(tfdiags.Sourceless(
   437  				tfdiags.Warning,
   438  				"Missing backend configuration",
   439  				`-backend-config was used without a "backend" block in the configuration.
   440  
   441  If you intended to override the default local backend configuration,
   442  no action is required, but you may add an explicit backend block to your
   443  configuration to clear this warning:
   444  
   445  terraform {
   446    backend "local" {}
   447  }
   448  
   449  However, if you intended to override a defined backend, please verify that
   450  the backend configuration is present and valid.
   451  `,
   452  			))
   453  		}
   454  	}
   455  
   456  	opts := &BackendOpts{
   457  		Config:         backendConfig,
   458  		ConfigOverride: backendConfigOverride,
   459  		Init:           true,
   460  	}
   461  
   462  	back, backDiags := c.Backend(opts)
   463  	diags = diags.Append(backDiags)
   464  	return back, true, diags
   465  }
   466  
   467  // Load the complete module tree, and fetch any missing providers.
   468  // This method outputs its own Ui.
   469  func (c *InitCommand) getProviders(config *configs.Config, state *states.State, upgrade bool, pluginDirs []string, flagLockfile string) (output, abort bool, diags tfdiags.Diagnostics) {
   470  	// Dev overrides cause the result of "terraform init" to be irrelevant for
   471  	// any overridden providers, so we'll warn about it to avoid later
   472  	// confusion when Terraform ends up using a different provider than the
   473  	// lock file called for.
   474  	diags = diags.Append(c.providerDevOverrideInitWarnings())
   475  
   476  	// First we'll collect all the provider dependencies we can see in the
   477  	// configuration and the state.
   478  	reqs, hclDiags := config.ProviderRequirements()
   479  	diags = diags.Append(hclDiags)
   480  	if hclDiags.HasErrors() {
   481  		return false, true, diags
   482  	}
   483  	if state != nil {
   484  		stateReqs := state.ProviderRequirements()
   485  		reqs = reqs.Merge(stateReqs)
   486  	}
   487  
   488  	for providerAddr := range reqs {
   489  		if providerAddr.IsLegacy() {
   490  			diags = diags.Append(tfdiags.Sourceless(
   491  				tfdiags.Error,
   492  				"Invalid legacy provider address",
   493  				fmt.Sprintf(
   494  					"This configuration or its associated state refers to the unqualified provider %q.\n\nYou must complete the Terraform 0.13 upgrade process before upgrading to later versions.",
   495  					providerAddr.Type,
   496  				),
   497  			))
   498  		}
   499  	}
   500  
   501  	previousLocks, moreDiags := c.lockedDependencies()
   502  	diags = diags.Append(moreDiags)
   503  
   504  	if diags.HasErrors() {
   505  		return false, true, diags
   506  	}
   507  
   508  	var inst *providercache.Installer
   509  	if len(pluginDirs) == 0 {
   510  		// By default we use a source that looks for providers in all of the
   511  		// standard locations, possibly customized by the user in CLI config.
   512  		inst = c.providerInstaller()
   513  	} else {
   514  		// If the user passes at least one -plugin-dir then that circumvents
   515  		// the usual sources and forces Terraform to consult only the given
   516  		// directories. Anything not available in one of those directories
   517  		// is not available for installation.
   518  		source := c.providerCustomLocalDirectorySource(pluginDirs)
   519  		inst = c.providerInstallerCustomSource(source)
   520  
   521  		// The default (or configured) search paths are logged earlier, in provider_source.go
   522  		// Log that those are being overridden by the `-plugin-dir` command line options
   523  		log.Println("[DEBUG] init: overriding provider plugin search paths")
   524  		log.Printf("[DEBUG] will search for provider plugins in %s", pluginDirs)
   525  	}
   526  
   527  	// Installation can be aborted by interruption signals
   528  	ctx, done := c.InterruptibleContext()
   529  	defer done()
   530  
   531  	// Because we're currently just streaming a series of events sequentially
   532  	// into the terminal, we're showing only a subset of the events to keep
   533  	// things relatively concise. Later it'd be nice to have a progress UI
   534  	// where statuses update in-place, but we can't do that as long as we
   535  	// are shimming our vt100 output to the legacy console API on Windows.
   536  	evts := &providercache.InstallerEvents{
   537  		PendingProviders: func(reqs map[addrs.Provider]getproviders.VersionConstraints) {
   538  			c.Ui.Output(c.Colorize().Color(
   539  				"\n[reset][bold]Initializing provider plugins...",
   540  			))
   541  		},
   542  		ProviderAlreadyInstalled: func(provider addrs.Provider, selectedVersion getproviders.Version) {
   543  			c.Ui.Info(fmt.Sprintf("- Using previously-installed %s v%s", provider.ForDisplay(), selectedVersion))
   544  		},
   545  		BuiltInProviderAvailable: func(provider addrs.Provider) {
   546  			c.Ui.Info(fmt.Sprintf("- %s is built in to Terraform", provider.ForDisplay()))
   547  		},
   548  		BuiltInProviderFailure: func(provider addrs.Provider, err error) {
   549  			diags = diags.Append(tfdiags.Sourceless(
   550  				tfdiags.Error,
   551  				"Invalid dependency on built-in provider",
   552  				fmt.Sprintf("Cannot use %s: %s.", provider.ForDisplay(), err),
   553  			))
   554  		},
   555  		QueryPackagesBegin: func(provider addrs.Provider, versionConstraints getproviders.VersionConstraints, locked bool) {
   556  			if locked {
   557  				c.Ui.Info(fmt.Sprintf("- Reusing previous version of %s from the dependency lock file", provider.ForDisplay()))
   558  			} else {
   559  				if len(versionConstraints) > 0 {
   560  					c.Ui.Info(fmt.Sprintf("- Finding %s versions matching %q...", provider.ForDisplay(), getproviders.VersionConstraintsString(versionConstraints)))
   561  				} else {
   562  					c.Ui.Info(fmt.Sprintf("- Finding latest version of %s...", provider.ForDisplay()))
   563  				}
   564  			}
   565  		},
   566  		LinkFromCacheBegin: func(provider addrs.Provider, version getproviders.Version, cacheRoot string) {
   567  			c.Ui.Info(fmt.Sprintf("- Using %s v%s from the shared cache directory", provider.ForDisplay(), version))
   568  		},
   569  		FetchPackageBegin: func(provider addrs.Provider, version getproviders.Version, location getproviders.PackageLocation) {
   570  			c.Ui.Info(fmt.Sprintf("- Installing %s v%s...", provider.ForDisplay(), version))
   571  		},
   572  		QueryPackagesFailure: func(provider addrs.Provider, err error) {
   573  			switch errorTy := err.(type) {
   574  			case getproviders.ErrProviderNotFound:
   575  				sources := errorTy.Sources
   576  				displaySources := make([]string, len(sources))
   577  				for i, source := range sources {
   578  					displaySources[i] = fmt.Sprintf("  - %s", source)
   579  				}
   580  				diags = diags.Append(tfdiags.Sourceless(
   581  					tfdiags.Error,
   582  					"Failed to query available provider packages",
   583  					fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s\n\n%s",
   584  						provider.ForDisplay(), err, strings.Join(displaySources, "\n"),
   585  					),
   586  				))
   587  			case getproviders.ErrRegistryProviderNotKnown:
   588  				// We might be able to suggest an alternative provider to use
   589  				// instead of this one.
   590  				suggestion := fmt.Sprintf("\n\nAll modules should specify their required_providers so that external consumers will get the correct providers when using a module. To see which modules are currently depending on %s, run the following command:\n    terraform providers", provider.ForDisplay())
   591  				alternative := getproviders.MissingProviderSuggestion(ctx, provider, inst.ProviderSource(), reqs)
   592  				if alternative != provider {
   593  					suggestion = fmt.Sprintf(
   594  						"\n\nDid you intend to use %s? If so, you must specify that source address in each module which requires that provider. To see which modules are currently depending on %s, run the following command:\n    terraform providers",
   595  						alternative.ForDisplay(), provider.ForDisplay(),
   596  					)
   597  				}
   598  
   599  				diags = diags.Append(tfdiags.Sourceless(
   600  					tfdiags.Error,
   601  					"Failed to query available provider packages",
   602  					fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s%s",
   603  						provider.ForDisplay(), err, suggestion,
   604  					),
   605  				))
   606  			case getproviders.ErrHostNoProviders:
   607  				switch {
   608  				case errorTy.Hostname == svchost.Hostname("github.com") && !errorTy.HasOtherVersion:
   609  					// If a user copies the URL of a GitHub repository into
   610  					// the source argument and removes the schema to make it
   611  					// provider-address-shaped then that's one way we can end up
   612  					// here. We'll use a specialized error message in anticipation
   613  					// of that mistake. We only do this if github.com isn't a
   614  					// provider registry, to allow for the (admittedly currently
   615  					// rather unlikely) possibility that github.com starts being
   616  					// a real Terraform provider registry in the future.
   617  					diags = diags.Append(tfdiags.Sourceless(
   618  						tfdiags.Error,
   619  						"Invalid provider registry host",
   620  						fmt.Sprintf("The given source address %q specifies a GitHub repository rather than a Terraform provider. Refer to the documentation of the provider to find the correct source address to use.",
   621  							provider.String(),
   622  						),
   623  					))
   624  
   625  				case errorTy.HasOtherVersion:
   626  					diags = diags.Append(tfdiags.Sourceless(
   627  						tfdiags.Error,
   628  						"Invalid provider registry host",
   629  						fmt.Sprintf("The host %q given in in provider source address %q does not offer a Terraform provider registry that is compatible with this Terraform version, but it may be compatible with a different Terraform version.",
   630  							errorTy.Hostname, provider.String(),
   631  						),
   632  					))
   633  
   634  				default:
   635  					diags = diags.Append(tfdiags.Sourceless(
   636  						tfdiags.Error,
   637  						"Invalid provider registry host",
   638  						fmt.Sprintf("The host %q given in in provider source address %q does not offer a Terraform provider registry.",
   639  							errorTy.Hostname, provider.String(),
   640  						),
   641  					))
   642  				}
   643  
   644  			case getproviders.ErrRequestCanceled:
   645  				// We don't attribute cancellation to any particular operation,
   646  				// but rather just emit a single general message about it at
   647  				// the end, by checking ctx.Err().
   648  
   649  			default:
   650  				diags = diags.Append(tfdiags.Sourceless(
   651  					tfdiags.Error,
   652  					"Failed to query available provider packages",
   653  					fmt.Sprintf("Could not retrieve the list of available versions for provider %s: %s",
   654  						provider.ForDisplay(), err,
   655  					),
   656  				))
   657  			}
   658  
   659  		},
   660  		QueryPackagesWarning: func(provider addrs.Provider, warnings []string) {
   661  			displayWarnings := make([]string, len(warnings))
   662  			for i, warning := range warnings {
   663  				displayWarnings[i] = fmt.Sprintf("- %s", warning)
   664  			}
   665  
   666  			diags = diags.Append(tfdiags.Sourceless(
   667  				tfdiags.Warning,
   668  				"Additional provider information from registry",
   669  				fmt.Sprintf("The remote registry returned warnings for %s:\n%s",
   670  					provider.String(),
   671  					strings.Join(displayWarnings, "\n"),
   672  				),
   673  			))
   674  		},
   675  		LinkFromCacheFailure: func(provider addrs.Provider, version getproviders.Version, err error) {
   676  			diags = diags.Append(tfdiags.Sourceless(
   677  				tfdiags.Error,
   678  				"Failed to install provider from shared cache",
   679  				fmt.Sprintf("Error while importing %s v%s from the shared cache directory: %s.", provider.ForDisplay(), version, err),
   680  			))
   681  		},
   682  		FetchPackageFailure: func(provider addrs.Provider, version getproviders.Version, err error) {
   683  			const summaryIncompatible = "Incompatible provider version"
   684  			switch err := err.(type) {
   685  			case getproviders.ErrProtocolNotSupported:
   686  				closestAvailable := err.Suggestion
   687  				switch {
   688  				case closestAvailable == getproviders.UnspecifiedVersion:
   689  					diags = diags.Append(tfdiags.Sourceless(
   690  						tfdiags.Error,
   691  						summaryIncompatible,
   692  						fmt.Sprintf(errProviderVersionIncompatible, provider.String()),
   693  					))
   694  				case version.GreaterThan(closestAvailable):
   695  					diags = diags.Append(tfdiags.Sourceless(
   696  						tfdiags.Error,
   697  						summaryIncompatible,
   698  						fmt.Sprintf(providerProtocolTooNew, provider.ForDisplay(),
   699  							version, tfversion.String(), closestAvailable, closestAvailable,
   700  							getproviders.VersionConstraintsString(reqs[provider]),
   701  						),
   702  					))
   703  				default: // version is less than closestAvailable
   704  					diags = diags.Append(tfdiags.Sourceless(
   705  						tfdiags.Error,
   706  						summaryIncompatible,
   707  						fmt.Sprintf(providerProtocolTooOld, provider.ForDisplay(),
   708  							version, tfversion.String(), closestAvailable, closestAvailable,
   709  							getproviders.VersionConstraintsString(reqs[provider]),
   710  						),
   711  					))
   712  				}
   713  			case getproviders.ErrPlatformNotSupported:
   714  				switch {
   715  				case err.MirrorURL != nil:
   716  					// If we're installing from a mirror then it may just be
   717  					// the mirror lacking the package, rather than it being
   718  					// unavailable from upstream.
   719  					diags = diags.Append(tfdiags.Sourceless(
   720  						tfdiags.Error,
   721  						summaryIncompatible,
   722  						fmt.Sprintf(
   723  							"Your chosen provider mirror at %s does not have a %s v%s package available for your current platform, %s.\n\nProvider releases are separate from Terraform CLI releases, so this provider might not support your current platform. Alternatively, the mirror itself might have only a subset of the plugin packages available in the origin registry, at %s.",
   724  							err.MirrorURL, err.Provider, err.Version, err.Platform,
   725  							err.Provider.Hostname,
   726  						),
   727  					))
   728  				default:
   729  					diags = diags.Append(tfdiags.Sourceless(
   730  						tfdiags.Error,
   731  						summaryIncompatible,
   732  						fmt.Sprintf(
   733  							"Provider %s v%s does not have a package available for your current platform, %s.\n\nProvider releases are separate from Terraform CLI releases, so not all providers are available for all platforms. Other versions of this provider may have different platforms supported.",
   734  							err.Provider, err.Version, err.Platform,
   735  						),
   736  					))
   737  				}
   738  
   739  			case getproviders.ErrRequestCanceled:
   740  				// We don't attribute cancellation to any particular operation,
   741  				// but rather just emit a single general message about it at
   742  				// the end, by checking ctx.Err().
   743  
   744  			default:
   745  				// We can potentially end up in here under cancellation too,
   746  				// in spite of our getproviders.ErrRequestCanceled case above,
   747  				// because not all of the outgoing requests we do under the
   748  				// "fetch package" banner are source metadata requests.
   749  				// In that case we will emit a redundant error here about
   750  				// the request being cancelled, but we'll still detect it
   751  				// as a cancellation after the installer returns and do the
   752  				// normal cancellation handling.
   753  
   754  				diags = diags.Append(tfdiags.Sourceless(
   755  					tfdiags.Error,
   756  					"Failed to install provider",
   757  					fmt.Sprintf("Error while installing %s v%s: %s", provider.ForDisplay(), version, err),
   758  				))
   759  			}
   760  		},
   761  		FetchPackageSuccess: func(provider addrs.Provider, version getproviders.Version, localDir string, authResult *getproviders.PackageAuthenticationResult) {
   762  			var keyID string
   763  			if authResult != nil && authResult.ThirdPartySigned() {
   764  				keyID = authResult.KeyID
   765  			}
   766  			if keyID != "" {
   767  				keyID = c.Colorize().Color(fmt.Sprintf(", key ID [reset][bold]%s[reset]", keyID))
   768  			}
   769  
   770  			c.Ui.Info(fmt.Sprintf("- Installed %s v%s (%s%s)", provider.ForDisplay(), version, authResult, keyID))
   771  		},
   772  		ProvidersFetched: func(authResults map[addrs.Provider]*getproviders.PackageAuthenticationResult) {
   773  			thirdPartySigned := false
   774  			for _, authResult := range authResults {
   775  				if authResult.ThirdPartySigned() {
   776  					thirdPartySigned = true
   777  					break
   778  				}
   779  			}
   780  			if thirdPartySigned {
   781  				c.Ui.Info(fmt.Sprintf("\nPartner and community providers are signed by their developers.\n" +
   782  					"If you'd like to know more about provider signing, you can read about it here:\n" +
   783  					"https://www.terraform.io/docs/cli/plugins/signing.html"))
   784  			}
   785  		},
   786  		HashPackageFailure: func(provider addrs.Provider, version getproviders.Version, err error) {
   787  			diags = diags.Append(tfdiags.Sourceless(
   788  				tfdiags.Error,
   789  				"Failed to validate installed provider",
   790  				fmt.Sprintf(
   791  					"Validating provider %s v%s failed: %s",
   792  					provider.ForDisplay(),
   793  					version,
   794  					err,
   795  				),
   796  			))
   797  		},
   798  	}
   799  	ctx = evts.OnContext(ctx)
   800  
   801  	mode := providercache.InstallNewProvidersOnly
   802  	if upgrade {
   803  		if flagLockfile == "readonly" {
   804  			c.Ui.Error("The -upgrade flag conflicts with -lockfile=readonly.")
   805  			return true, true, diags
   806  		}
   807  
   808  		mode = providercache.InstallUpgrades
   809  	}
   810  	newLocks, err := inst.EnsureProviderVersions(ctx, previousLocks, reqs, mode)
   811  	if ctx.Err() == context.Canceled {
   812  		c.showDiagnostics(diags)
   813  		c.Ui.Error("Provider installation was canceled by an interrupt signal.")
   814  		return true, true, diags
   815  	}
   816  	if err != nil {
   817  		// The errors captured in "err" should be redundant with what we
   818  		// received via the InstallerEvents callbacks above, so we'll
   819  		// just return those as long as we have some.
   820  		if !diags.HasErrors() {
   821  			diags = diags.Append(err)
   822  		}
   823  
   824  		return true, true, diags
   825  	}
   826  
   827  	// If the provider dependencies have changed since the last run then we'll
   828  	// say a little about that in case the reader wasn't expecting a change.
   829  	// (When we later integrate module dependencies into the lock file we'll
   830  	// probably want to refactor this so that we produce one lock-file related
   831  	// message for all changes together, but this is here for now just because
   832  	// it's the smallest change relative to what came before it, which was
   833  	// a hidden JSON file specifically for tracking providers.)
   834  	if !newLocks.Equal(previousLocks) {
   835  		// if readonly mode
   836  		if flagLockfile == "readonly" {
   837  			// check if required provider dependences change
   838  			if !newLocks.EqualProviderAddress(previousLocks) {
   839  				diags = diags.Append(tfdiags.Sourceless(
   840  					tfdiags.Error,
   841  					`Provider dependency changes detected`,
   842  					`Changes to the required provider dependencies were detected, but the lock file is read-only. To use and record these requirements, run "terraform init" without the "-lockfile=readonly" flag.`,
   843  				))
   844  				return true, true, diags
   845  			}
   846  
   847  			// suppress updating the file to record any new information it learned,
   848  			// such as a hash using a new scheme.
   849  			diags = diags.Append(tfdiags.Sourceless(
   850  				tfdiags.Warning,
   851  				`Provider lock file not updated`,
   852  				`Changes to the provider selections were detected, but not saved in the .terraform.lock.hcl file. To record these selections, run "terraform init" without the "-lockfile=readonly" flag.`,
   853  			))
   854  			return true, false, diags
   855  		}
   856  
   857  		if previousLocks.Empty() {
   858  			// A change from empty to non-empty is special because it suggests
   859  			// we're running "terraform init" for the first time against a
   860  			// new configuration. In that case we'll take the opportunity to
   861  			// say a little about what the dependency lock file is, for new
   862  			// users or those who are upgrading from a previous Terraform
   863  			// version that didn't have dependency lock files.
   864  			c.Ui.Output(c.Colorize().Color(`
   865  Terraform has created a lock file [bold].terraform.lock.hcl[reset] to record the provider
   866  selections it made above. Include this file in your version control repository
   867  so that Terraform can guarantee to make the same selections by default when
   868  you run "terraform init" in the future.`))
   869  		} else {
   870  			c.Ui.Output(c.Colorize().Color(`
   871  Terraform has made some changes to the provider dependency selections recorded
   872  in the .terraform.lock.hcl file. Review those changes and commit them to your
   873  version control system if they represent changes you intended to make.`))
   874  		}
   875  
   876  		moreDiags = c.replaceLockedDependencies(newLocks)
   877  		diags = diags.Append(moreDiags)
   878  	}
   879  
   880  	return true, false, diags
   881  }
   882  
   883  // backendConfigOverrideBody interprets the raw values of -backend-config
   884  // arguments into a hcl Body that should override the backend settings given
   885  // in the configuration.
   886  //
   887  // If the result is nil then no override needs to be provided.
   888  //
   889  // If the returned diagnostics contains errors then the returned body may be
   890  // incomplete or invalid.
   891  func (c *InitCommand) backendConfigOverrideBody(flags rawFlags, schema *configschema.Block) (hcl.Body, tfdiags.Diagnostics) {
   892  	items := flags.AllItems()
   893  	if len(items) == 0 {
   894  		return nil, nil
   895  	}
   896  
   897  	var ret hcl.Body
   898  	var diags tfdiags.Diagnostics
   899  	synthVals := make(map[string]cty.Value)
   900  
   901  	mergeBody := func(newBody hcl.Body) {
   902  		if ret == nil {
   903  			ret = newBody
   904  		} else {
   905  			ret = configs.MergeBodies(ret, newBody)
   906  		}
   907  	}
   908  	flushVals := func() {
   909  		if len(synthVals) == 0 {
   910  			return
   911  		}
   912  		newBody := configs.SynthBody("-backend-config=...", synthVals)
   913  		mergeBody(newBody)
   914  		synthVals = make(map[string]cty.Value)
   915  	}
   916  
   917  	if len(items) == 1 && items[0].Value == "" {
   918  		// Explicitly remove all -backend-config options.
   919  		// We do this by setting an empty but non-nil ConfigOverrides.
   920  		return configs.SynthBody("-backend-config=''", synthVals), diags
   921  	}
   922  
   923  	for _, item := range items {
   924  		eq := strings.Index(item.Value, "=")
   925  
   926  		if eq == -1 {
   927  			// The value is interpreted as a filename.
   928  			newBody, fileDiags := c.loadHCLFile(item.Value)
   929  			diags = diags.Append(fileDiags)
   930  			if fileDiags.HasErrors() {
   931  				continue
   932  			}
   933  			// Generate an HCL body schema for the backend block.
   934  			var bodySchema hcl.BodySchema
   935  			for name := range schema.Attributes {
   936  				// We intentionally ignore the `Required` attribute here
   937  				// because backend config override files can be partial. The
   938  				// goal is to make sure we're not loading a file with
   939  				// extraneous attributes or blocks.
   940  				bodySchema.Attributes = append(bodySchema.Attributes, hcl.AttributeSchema{
   941  					Name: name,
   942  				})
   943  			}
   944  			for name, block := range schema.BlockTypes {
   945  				var labelNames []string
   946  				if block.Nesting == configschema.NestingMap {
   947  					labelNames = append(labelNames, "key")
   948  				}
   949  				bodySchema.Blocks = append(bodySchema.Blocks, hcl.BlockHeaderSchema{
   950  					Type:       name,
   951  					LabelNames: labelNames,
   952  				})
   953  			}
   954  			// Verify that the file body matches the expected backend schema.
   955  			_, schemaDiags := newBody.Content(&bodySchema)
   956  			diags = diags.Append(schemaDiags)
   957  			if schemaDiags.HasErrors() {
   958  				continue
   959  			}
   960  			flushVals() // deal with any accumulated individual values first
   961  			mergeBody(newBody)
   962  		} else {
   963  			name := item.Value[:eq]
   964  			rawValue := item.Value[eq+1:]
   965  			attrS := schema.Attributes[name]
   966  			if attrS == nil {
   967  				diags = diags.Append(tfdiags.Sourceless(
   968  					tfdiags.Error,
   969  					"Invalid backend configuration argument",
   970  					fmt.Sprintf("The backend configuration argument %q given on the command line is not expected for the selected backend type.", name),
   971  				))
   972  				continue
   973  			}
   974  			value, valueDiags := configValueFromCLI(item.String(), rawValue, attrS.Type)
   975  			diags = diags.Append(valueDiags)
   976  			if valueDiags.HasErrors() {
   977  				continue
   978  			}
   979  			synthVals[name] = value
   980  		}
   981  	}
   982  
   983  	flushVals()
   984  
   985  	return ret, diags
   986  }
   987  
   988  func (c *InitCommand) AutocompleteArgs() complete.Predictor {
   989  	return complete.PredictDirs("")
   990  }
   991  
   992  func (c *InitCommand) AutocompleteFlags() complete.Flags {
   993  	return complete.Flags{
   994  		"-backend":        completePredictBoolean,
   995  		"-backend-config": complete.PredictFiles("*.tfvars"), // can also be key=value, but we can't "predict" that
   996  		"-force-copy":     complete.PredictNothing,
   997  		"-from-module":    completePredictModuleSource,
   998  		"-get":            completePredictBoolean,
   999  		"-input":          completePredictBoolean,
  1000  		"-lock":           completePredictBoolean,
  1001  		"-lock-timeout":   complete.PredictAnything,
  1002  		"-no-color":       complete.PredictNothing,
  1003  		"-plugin-dir":     complete.PredictDirs(""),
  1004  		"-reconfigure":    complete.PredictNothing,
  1005  		"-migrate-state":  complete.PredictNothing,
  1006  		"-upgrade":        completePredictBoolean,
  1007  	}
  1008  }
  1009  
  1010  func (c *InitCommand) Help() string {
  1011  	helpText := `
  1012  Usage: terraform [global options] init [options]
  1013  
  1014    Initialize a new or existing Terraform working directory by creating
  1015    initial files, loading any remote state, downloading modules, etc.
  1016  
  1017    This is the first command that should be run for any new or existing
  1018    Terraform configuration per machine. This sets up all the local data
  1019    necessary to run Terraform that is typically not committed to version
  1020    control.
  1021  
  1022    This command is always safe to run multiple times. Though subsequent runs
  1023    may give errors, this command will never delete your configuration or
  1024    state. Even so, if you have important information, please back it up prior
  1025    to running this command, just in case.
  1026  
  1027  Options:
  1028  
  1029    -backend=false          Disable backend initialization for this configuration
  1030                            and use the previously initialized backend instead.
  1031  
  1032    -backend-config=path    This can be either a path to an HCL file with key/value
  1033                            assignments (same format as terraform.tfvars) or a
  1034                            'key=value' format. This is merged with what is in the
  1035                            configuration file. This can be specified multiple
  1036                            times. The backend type must be in the configuration
  1037                            itself.
  1038  
  1039    -force-copy             Suppress prompts about copying state data. This is
  1040                            equivalent to providing a "yes" to all confirmation
  1041                            prompts.
  1042  
  1043    -from-module=SOURCE     Copy the contents of the given module into the target
  1044                            directory before initialization.
  1045  
  1046    -get=false              Disable downloading modules for this configuration.
  1047  
  1048    -input=false            Disable prompting for missing backend configuration
  1049                            values. This will result in an error if the backend
  1050                            configuration is not fully specified.
  1051  
  1052    -lock=false             Don't hold a state lock during backend migration.
  1053                            This is dangerous if others might concurrently run
  1054                            commands against the same workspace.
  1055  
  1056    -lock-timeout=0s        Duration to retry a state lock.
  1057  
  1058    -no-color               If specified, output won't contain any color.
  1059  
  1060    -plugin-dir             Directory containing plugin binaries. This overrides all
  1061                            default search paths for plugins, and prevents the
  1062                            automatic installation of plugins. This flag can be used
  1063                            multiple times.
  1064  
  1065    -reconfigure            Reconfigure the backend, ignoring any saved
  1066                            configuration.
  1067  
  1068    -migrate-state          Reconfigure the backend, and attempt to migrate any
  1069                            existing state.
  1070  
  1071    -upgrade                Install the latest module and provider versions
  1072                            allowed within configured constraints, overriding the
  1073                            default behavior of selecting exactly the version
  1074                            recorded in the dependency lockfile.
  1075  
  1076    -lockfile=MODE          Set a dependency lockfile mode.
  1077                            Currently only "readonly" is valid.
  1078  
  1079    -ignore-remote-version  A rare option used for the remote backend only. See
  1080                            the remote backend documentation for more information.
  1081  
  1082  `
  1083  	return strings.TrimSpace(helpText)
  1084  }
  1085  
  1086  func (c *InitCommand) Synopsis() string {
  1087  	return "Prepare your working directory for other commands"
  1088  }
  1089  
  1090  const errInitConfigError = `
  1091  [reset]There are some problems with the configuration, described below.
  1092  
  1093  The Terraform configuration must be valid before initialization so that
  1094  Terraform can determine which modules and providers need to be installed.
  1095  `
  1096  
  1097  const errInitCopyNotEmpty = `
  1098  The working directory already contains files. The -from-module option requires
  1099  an empty directory into which a copy of the referenced module will be placed.
  1100  
  1101  To initialize the configuration already in this working directory, omit the
  1102  -from-module option.
  1103  `
  1104  
  1105  const outputInitEmpty = `
  1106  [reset][bold]Terraform initialized in an empty directory![reset]
  1107  
  1108  The directory has no Terraform configuration files. You may begin working
  1109  with Terraform immediately by creating Terraform configuration files.
  1110  `
  1111  
  1112  const outputInitSuccess = `
  1113  [reset][bold][green]Terraform has been successfully initialized![reset][green]
  1114  `
  1115  
  1116  const outputInitSuccessCloud = `
  1117  [reset][bold][green]Terraform Cloud has been successfully initialized![reset][green]
  1118  `
  1119  
  1120  const outputInitSuccessCLI = `[reset][green]
  1121  You may now begin working with Terraform. Try running "terraform plan" to see
  1122  any changes that are required for your infrastructure. All Terraform commands
  1123  should now work.
  1124  
  1125  If you ever set or change modules or backend configuration for Terraform,
  1126  rerun this command to reinitialize your working directory. If you forget, other
  1127  commands will detect it and remind you to do so if necessary.
  1128  `
  1129  
  1130  const outputInitSuccessCLICloud = `[reset][green]
  1131  You may now begin working with Terraform Cloud. Try running "terraform plan" to
  1132  see any changes that are required for your infrastructure.
  1133  
  1134  If you ever set or change modules or Terraform Settings, run "terraform init"
  1135  again to reinitialize your working directory.
  1136  `
  1137  
  1138  // providerProtocolTooOld is a message sent to the CLI UI if the provider's
  1139  // supported protocol versions are too old for the user's version of terraform,
  1140  // but a newer version of the provider is compatible.
  1141  const providerProtocolTooOld = `Provider %q v%s is not compatible with Terraform %s.
  1142  Provider version %s is the latest compatible version. Select it with the following version constraint:
  1143  	version = %q
  1144  
  1145  Terraform checked all of the plugin versions matching the given constraint:
  1146  	%s
  1147  
  1148  Consult the documentation for this provider for more information on compatibility between provider and Terraform versions.
  1149  `
  1150  
  1151  // providerProtocolTooNew is a message sent to the CLI UI if the provider's
  1152  // supported protocol versions are too new for the user's version of terraform,
  1153  // and the user could either upgrade terraform or choose an older version of the
  1154  // provider.
  1155  const providerProtocolTooNew = `Provider %q v%s is not compatible with Terraform %s.
  1156  You need to downgrade to v%s or earlier. Select it with the following constraint:
  1157  	version = %q
  1158  
  1159  Terraform checked all of the plugin versions matching the given constraint:
  1160  	%s
  1161  
  1162  Consult the documentation for this provider for more information on compatibility between provider and Terraform versions.
  1163  Alternatively, upgrade to the latest version of Terraform for compatibility with newer provider releases.
  1164  `
  1165  
  1166  // No version of the provider is compatible.
  1167  const errProviderVersionIncompatible = `No compatible versions of provider %s were found.`