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