github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/command/init.go (about)

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