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