github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/init.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/hashicorp/hcl/v2"
    11  	"github.com/hashicorp/terraform-config-inspect/tfconfig"
    12  	"github.com/posener/complete"
    13  	"github.com/zclconf/go-cty/cty"
    14  
    15  	"github.com/hashicorp/errwrap"
    16  	"github.com/hashicorp/terraform/addrs"
    17  	"github.com/hashicorp/terraform/backend"
    18  	backendInit "github.com/hashicorp/terraform/backend/init"
    19  	"github.com/hashicorp/terraform/configs"
    20  	"github.com/hashicorp/terraform/configs/configschema"
    21  	"github.com/hashicorp/terraform/configs/configupgrade"
    22  	"github.com/hashicorp/terraform/internal/earlyconfig"
    23  	"github.com/hashicorp/terraform/internal/initwd"
    24  	"github.com/hashicorp/terraform/plugin/discovery"
    25  	"github.com/hashicorp/terraform/states"
    26  	"github.com/hashicorp/terraform/terraform"
    27  	"github.com/hashicorp/terraform/tfdiags"
    28  )
    29  
    30  // InitCommand is a Command implementation that takes a Terraform
    31  // module and clones it to the working directory.
    32  type InitCommand struct {
    33  	Meta
    34  
    35  	// getPlugins is for the -get-plugins flag
    36  	getPlugins bool
    37  
    38  	// providerInstaller is used to download and install providers that
    39  	// aren't found locally. This uses a discovery.ProviderInstaller instance
    40  	// by default, but it can be overridden here as a way to mock fetching
    41  	// providers for tests.
    42  	providerInstaller discovery.Installer
    43  }
    44  
    45  func (c *InitCommand) Run(args []string) int {
    46  	var flagFromModule string
    47  	var flagBackend, flagGet, flagUpgrade bool
    48  	var flagPluginPath FlagStringSlice
    49  	var flagVerifyPlugins bool
    50  	flagConfigExtra := newRawFlags("-backend-config")
    51  
    52  	args, err := c.Meta.process(args, false)
    53  	if err != nil {
    54  		return 1
    55  	}
    56  
    57  	cmdFlags := c.Meta.extendedFlagSet("init")
    58  	cmdFlags.BoolVar(&flagBackend, "backend", true, "")
    59  	cmdFlags.Var(flagConfigExtra, "backend-config", "")
    60  	cmdFlags.StringVar(&flagFromModule, "from-module", "", "copy the source of the given module into the directory before init")
    61  	cmdFlags.BoolVar(&flagGet, "get", true, "")
    62  	cmdFlags.BoolVar(&c.getPlugins, "get-plugins", true, "")
    63  	cmdFlags.BoolVar(&c.forceInitCopy, "force-copy", false, "suppress prompts about copying state data")
    64  	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
    65  	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
    66  	cmdFlags.BoolVar(&c.reconfigure, "reconfigure", false, "reconfigure")
    67  	cmdFlags.BoolVar(&flagUpgrade, "upgrade", false, "")
    68  	cmdFlags.Var(&flagPluginPath, "plugin-dir", "plugin directory")
    69  	cmdFlags.BoolVar(&flagVerifyPlugins, "verify-plugins", true, "verify plugins")
    70  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    71  	if err := cmdFlags.Parse(args); err != nil {
    72  		return 1
    73  	}
    74  
    75  	var diags tfdiags.Diagnostics
    76  
    77  	if len(flagPluginPath) > 0 {
    78  		c.pluginPath = flagPluginPath
    79  		c.getPlugins = false
    80  	}
    81  
    82  	// set providerInstaller if we don't have a test version already
    83  	if c.providerInstaller == nil {
    84  		c.providerInstaller = &discovery.ProviderInstaller{
    85  			Dir:                   c.pluginDir(),
    86  			Cache:                 c.pluginCache(),
    87  			PluginProtocolVersion: discovery.PluginInstallProtocolVersion,
    88  			SkipVerify:            !flagVerifyPlugins,
    89  			Ui:                    c.Ui,
    90  			Services:              c.Services,
    91  		}
    92  	}
    93  
    94  	// Validate the arg count
    95  	args = cmdFlags.Args()
    96  	if len(args) > 1 {
    97  		c.Ui.Error("The init command expects at most one argument.\n")
    98  		cmdFlags.Usage()
    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  	// Get our pwd. We don't always need it but always getting it is easier
   108  	// than the logic to determine if it is or isn't needed.
   109  	pwd, err := os.Getwd()
   110  	if err != nil {
   111  		c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
   112  		return 1
   113  	}
   114  
   115  	// If an argument is provided then it overrides our working directory.
   116  	path := pwd
   117  	if len(args) == 1 {
   118  		path = args[0]
   119  	}
   120  
   121  	// This will track whether we outputted anything so that we know whether
   122  	// to output a newline before the success message
   123  	var header bool
   124  
   125  	if flagFromModule != "" {
   126  		src := flagFromModule
   127  
   128  		empty, err := configs.IsEmptyDir(path)
   129  		if err != nil {
   130  			c.Ui.Error(fmt.Sprintf("Error validating destination directory: %s", err))
   131  			return 1
   132  		}
   133  		if !empty {
   134  			c.Ui.Error(strings.TrimSpace(errInitCopyNotEmpty))
   135  			return 1
   136  		}
   137  
   138  		c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
   139  			"[reset][bold]Copying configuration[reset] from %q...", src,
   140  		)))
   141  		header = true
   142  
   143  		hooks := uiModuleInstallHooks{
   144  			Ui:             c.Ui,
   145  			ShowLocalPaths: false, // since they are in a weird location for init
   146  		}
   147  
   148  		initDiags := c.initDirFromModule(path, src, hooks)
   149  		diags = diags.Append(initDiags)
   150  		if initDiags.HasErrors() {
   151  			c.showDiagnostics(diags)
   152  			return 1
   153  		}
   154  
   155  		c.Ui.Output("")
   156  	}
   157  
   158  	// If our directory is empty, then we're done. We can't get or setup
   159  	// the backend with an empty directory.
   160  	empty, err := configs.IsEmptyDir(path)
   161  	if err != nil {
   162  		diags = diags.Append(fmt.Errorf("Error checking configuration: %s", err))
   163  		return 1
   164  	}
   165  	if empty {
   166  		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitEmpty)))
   167  		return 0
   168  	}
   169  
   170  	// Before we do anything else, we'll try loading configuration with both
   171  	// our "normal" and "early" configuration codepaths. If early succeeds
   172  	// while normal fails, that strongly suggests that the configuration is
   173  	// using syntax that worked in 0.11 but no longer in 0.12, which requires
   174  	// some special behavior here to get the directory initialized just enough
   175  	// to run "terraform 0.12upgrade".
   176  	//
   177  	// FIXME: Once we reach 0.13 and remove 0.12upgrade, we should rework this
   178  	// so that we first use the early config to do a general compatibility
   179  	// check with dependencies, producing version-oriented error messages if
   180  	// dependencies aren't right, and only then use the real loader to deal
   181  	// with the backend configuration.
   182  	rootMod, confDiags := c.loadSingleModule(path)
   183  	diags = diags.Append(confDiags)
   184  
   185  	rootModEarly, earlyConfDiags := c.loadSingleModuleEarly(path)
   186  	configUpgradeProbablyNeeded := false
   187  	if confDiags.HasErrors() {
   188  		if earlyConfDiags.HasErrors() {
   189  			// If both parsers produced errors then we'll assume the config
   190  			// is _truly_ invalid and produce error messages as normal.
   191  			// Since this may be the user's first ever interaction with Terraform,
   192  			// we'll provide some additional context in this case.
   193  			c.Ui.Error(strings.TrimSpace(errInitConfigError))
   194  			c.showDiagnostics(diags)
   195  			return 1
   196  		}
   197  
   198  		// If _only_ the main loader produced errors then that suggests an
   199  		// upgrade may help. To give us more certainty here, we'll use the
   200  		// same heuristic that "terraform 0.12upgrade" uses to guess if a
   201  		// configuration has already been upgraded, to reduce the risk that
   202  		// we'll produce a misleading message if the problem is just a regular
   203  		// syntax error that the early loader just didn't catch.
   204  		sources, err := configupgrade.LoadModule(path)
   205  		if err == nil {
   206  			if already, _ := sources.MaybeAlreadyUpgraded(); already {
   207  				// Just report the errors as normal, then.
   208  				c.Ui.Error(strings.TrimSpace(errInitConfigError))
   209  				c.showDiagnostics(diags)
   210  				return 1
   211  			}
   212  		}
   213  		configUpgradeProbablyNeeded = true
   214  	}
   215  	if earlyConfDiags.HasErrors() {
   216  		// If _only_ the early loader encountered errors then that's unusual
   217  		// (it should generally be a superset of the normal loader) but we'll
   218  		// return those errors anyway since otherwise we'll probably get
   219  		// some weird behavior downstream. Errors from the early loader are
   220  		// generally not as high-quality since it has less context to work with.
   221  		c.Ui.Error(strings.TrimSpace(errInitConfigError))
   222  		diags = diags.Append(earlyConfDiags)
   223  		c.showDiagnostics(diags)
   224  		return 1
   225  	}
   226  
   227  	if flagGet {
   228  		modsOutput, modsDiags := c.getModules(path, rootModEarly, flagUpgrade)
   229  		diags = diags.Append(modsDiags)
   230  		if modsDiags.HasErrors() {
   231  			c.showDiagnostics(diags)
   232  			return 1
   233  		}
   234  		if modsOutput {
   235  			header = true
   236  		}
   237  	}
   238  
   239  	// With all of the modules (hopefully) installed, we can now try to load
   240  	// the whole configuration tree.
   241  	//
   242  	// Just as above, we'll try loading both with the early and normal config
   243  	// loaders here. Subsequent work will only use the early config, but
   244  	// loading both gives us an opportunity to prefer the better error messages
   245  	// from the normal loader if both fail.
   246  	_, confDiags = c.loadConfig(path)
   247  	earlyConfig, earlyConfDiags := c.loadConfigEarly(path)
   248  	if confDiags.HasErrors() && !configUpgradeProbablyNeeded {
   249  		c.Ui.Error(strings.TrimSpace(errInitConfigError))
   250  		diags = diags.Append(confDiags)
   251  		c.showDiagnostics(diags)
   252  		return 1
   253  	}
   254  	if earlyConfDiags.HasErrors() {
   255  		c.Ui.Error(strings.TrimSpace(errInitConfigError))
   256  		diags = diags.Append(earlyConfDiags)
   257  		c.showDiagnostics(diags)
   258  		return 1
   259  	}
   260  
   261  	{
   262  		// Before we go further, we'll check to make sure none of the modules
   263  		// in the configuration declare that they don't support this Terraform
   264  		// version, so we can produce a version-related error message rather
   265  		// than potentially-confusing downstream errors.
   266  		versionDiags := initwd.CheckCoreVersionRequirements(earlyConfig)
   267  		diags = diags.Append(versionDiags)
   268  		if versionDiags.HasErrors() {
   269  			c.showDiagnostics(diags)
   270  			return 1
   271  		}
   272  	}
   273  
   274  	var back backend.Backend
   275  	if flagBackend {
   276  		switch {
   277  		case configUpgradeProbablyNeeded:
   278  			diags = diags.Append(tfdiags.Sourceless(
   279  				tfdiags.Warning,
   280  				"Skipping backend initialization pending configuration upgrade",
   281  				// The "below" in this message is referring to the special
   282  				// note about running "terraform 0.12upgrade" that we'll
   283  				// print out at the end when configUpgradeProbablyNeeded is set.
   284  				"The root module configuration contains errors that may be fixed by running the configuration upgrade tool, so Terraform is skipping backend initialization. See below for more information.",
   285  			))
   286  		default:
   287  			be, backendOutput, backendDiags := c.initBackend(rootMod, flagConfigExtra)
   288  			diags = diags.Append(backendDiags)
   289  			if backendDiags.HasErrors() {
   290  				c.showDiagnostics(diags)
   291  				return 1
   292  			}
   293  			if backendOutput {
   294  				header = true
   295  			}
   296  			back = be
   297  		}
   298  	} else {
   299  		// load the previously-stored backend config
   300  		be, backendDiags := c.Meta.backendFromState()
   301  		diags = diags.Append(backendDiags)
   302  		if backendDiags.HasErrors() {
   303  			c.showDiagnostics(diags)
   304  			return 1
   305  		}
   306  		back = be
   307  	}
   308  
   309  	if back == nil {
   310  		// If we didn't initialize a backend then we'll try to at least
   311  		// instantiate one. This might fail if it wasn't already initialized
   312  		// by a previous run, so we must still expect that "back" may be nil
   313  		// in code that follows.
   314  		var backDiags tfdiags.Diagnostics
   315  		back, backDiags = c.Backend(nil)
   316  		if backDiags.HasErrors() {
   317  			// This is fine. We'll proceed with no backend, then.
   318  			back = nil
   319  		}
   320  	}
   321  
   322  	var state *states.State
   323  
   324  	// If we have a functional backend (either just initialized or initialized
   325  	// on a previous run) we'll use the current state as a potential source
   326  	// of provider dependencies.
   327  	if back != nil {
   328  		sMgr, err := back.StateMgr(c.Workspace())
   329  		if err != nil {
   330  			c.Ui.Error(fmt.Sprintf("Error loading state: %s", err))
   331  			return 1
   332  		}
   333  
   334  		if err := sMgr.RefreshState(); err != nil {
   335  			c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
   336  			return 1
   337  		}
   338  
   339  		state = sMgr.State()
   340  	}
   341  
   342  	if v := os.Getenv(ProviderSkipVerifyEnvVar); v != "" {
   343  		c.ignorePluginChecksum = true
   344  	}
   345  
   346  	// Now that we have loaded all modules, check the module tree for missing providers.
   347  	providersOutput, providerDiags := c.getProviders(earlyConfig, state, flagUpgrade)
   348  	diags = diags.Append(providerDiags)
   349  	if providerDiags.HasErrors() {
   350  		c.showDiagnostics(diags)
   351  		return 1
   352  	}
   353  	if providersOutput {
   354  		header = true
   355  	}
   356  
   357  	// If we outputted information, then we need to output a newline
   358  	// so that our success message is nicely spaced out from prior text.
   359  	if header {
   360  		c.Ui.Output("")
   361  	}
   362  
   363  	// If we accumulated any warnings along the way that weren't accompanied
   364  	// by errors then we'll output them here so that the success message is
   365  	// still the final thing shown.
   366  	c.showDiagnostics(diags)
   367  
   368  	if configUpgradeProbablyNeeded {
   369  		switch {
   370  		case c.RunningInAutomation:
   371  			c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccessConfigUpgrade)))
   372  		default:
   373  			c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccessConfigUpgradeCLI)))
   374  		}
   375  		return 0
   376  	}
   377  	c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccess)))
   378  	if !c.RunningInAutomation {
   379  		// If we're not running in an automation wrapper, give the user
   380  		// some more detailed next steps that are appropriate for interactive
   381  		// shell usage.
   382  		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccessCLI)))
   383  	}
   384  
   385  	return 0
   386  }
   387  
   388  func (c *InitCommand) getModules(path string, earlyRoot *tfconfig.Module, upgrade bool) (output bool, diags tfdiags.Diagnostics) {
   389  	if len(earlyRoot.ModuleCalls) == 0 {
   390  		// Nothing to do
   391  		return false, nil
   392  	}
   393  
   394  	if upgrade {
   395  		c.Ui.Output(c.Colorize().Color(fmt.Sprintf("[reset][bold]Upgrading modules...")))
   396  	} else {
   397  		c.Ui.Output(c.Colorize().Color(fmt.Sprintf("[reset][bold]Initializing modules...")))
   398  	}
   399  
   400  	hooks := uiModuleInstallHooks{
   401  		Ui:             c.Ui,
   402  		ShowLocalPaths: true,
   403  	}
   404  	instDiags := c.installModules(path, upgrade, hooks)
   405  	diags = diags.Append(instDiags)
   406  
   407  	// Since module installer has modified the module manifest on disk, we need
   408  	// to refresh the cache of it in the loader.
   409  	if c.configLoader != nil {
   410  		if err := c.configLoader.RefreshModules(); err != nil {
   411  			// Should never happen
   412  			diags = diags.Append(tfdiags.Sourceless(
   413  				tfdiags.Error,
   414  				"Failed to read module manifest",
   415  				fmt.Sprintf("After installing modules, Terraform could not re-read the manifest of installed modules. This is a bug in Terraform. %s.", err),
   416  			))
   417  		}
   418  	}
   419  
   420  	return true, diags
   421  }
   422  
   423  func (c *InitCommand) initBackend(root *configs.Module, extraConfig rawFlags) (be backend.Backend, output bool, diags tfdiags.Diagnostics) {
   424  	c.Ui.Output(c.Colorize().Color(fmt.Sprintf("\n[reset][bold]Initializing the backend...")))
   425  
   426  	var backendConfig *configs.Backend
   427  	var backendConfigOverride hcl.Body
   428  	if root.Backend != nil {
   429  		backendType := root.Backend.Type
   430  		bf := backendInit.Backend(backendType)
   431  		if bf == nil {
   432  			diags = diags.Append(&hcl.Diagnostic{
   433  				Severity: hcl.DiagError,
   434  				Summary:  "Unsupported backend type",
   435  				Detail:   fmt.Sprintf("There is no backend type named %q.", backendType),
   436  				Subject:  &root.Backend.TypeRange,
   437  			})
   438  			return nil, true, diags
   439  		}
   440  
   441  		b := bf()
   442  		backendSchema := b.ConfigSchema()
   443  		backendConfig = root.Backend
   444  
   445  		var overrideDiags tfdiags.Diagnostics
   446  		backendConfigOverride, overrideDiags = c.backendConfigOverrideBody(extraConfig, backendSchema)
   447  		diags = diags.Append(overrideDiags)
   448  		if overrideDiags.HasErrors() {
   449  			return nil, true, diags
   450  		}
   451  	} else {
   452  		// If the user supplied a -backend-config on the CLI but no backend
   453  		// block was found in the configuration, it's likely - but not
   454  		// necessarily - a mistake. Return a warning.
   455  		if !extraConfig.Empty() {
   456  			diags = diags.Append(tfdiags.Sourceless(
   457  				tfdiags.Warning,
   458  				"Missing backend configuration",
   459  				`-backend-config was used without a "backend" block in the configuration.
   460  
   461  If you intended to override the default local backend configuration,
   462  no action is required, but you may add an explicit backend block to your
   463  configuration to clear this warning:
   464  
   465  terraform {
   466    backend "local" {}
   467  }
   468  
   469  However, if you intended to override a defined backend, please verify that
   470  the backend configuration is present and valid.
   471  `,
   472  			))
   473  		}
   474  	}
   475  
   476  	opts := &BackendOpts{
   477  		Config:         backendConfig,
   478  		ConfigOverride: backendConfigOverride,
   479  		Init:           true,
   480  	}
   481  
   482  	back, backDiags := c.Backend(opts)
   483  	diags = diags.Append(backDiags)
   484  	return back, true, diags
   485  }
   486  
   487  // Load the complete module tree, and fetch any missing providers.
   488  // This method outputs its own Ui.
   489  func (c *InitCommand) getProviders(earlyConfig *earlyconfig.Config, state *states.State, upgrade bool) (output bool, diags tfdiags.Diagnostics) {
   490  	var available discovery.PluginMetaSet
   491  	if upgrade {
   492  		// If we're in upgrade mode, we ignore any auto-installed plugins
   493  		// in "available", causing us to reinstall and possibly upgrade them.
   494  		available = c.providerPluginManuallyInstalledSet()
   495  	} else {
   496  		available = c.providerPluginSet()
   497  	}
   498  
   499  	configDeps, depsDiags := earlyConfig.ProviderDependencies()
   500  	diags = diags.Append(depsDiags)
   501  	if depsDiags.HasErrors() {
   502  		return false, diags
   503  	}
   504  
   505  	configReqs := configDeps.AllPluginRequirements()
   506  	// FIXME: This is weird because ConfigTreeDependencies was written before
   507  	// we switched over to using earlyConfig as the main source of dependencies.
   508  	// In future we should clean this up to be a more reasonable API.
   509  	stateReqs := terraform.ConfigTreeDependencies(nil, state).AllPluginRequirements()
   510  
   511  	requirements := configReqs.Merge(stateReqs)
   512  	if len(requirements) == 0 {
   513  		// nothing to initialize
   514  		return false, nil
   515  	}
   516  
   517  	c.Ui.Output(c.Colorize().Color(
   518  		"\n[reset][bold]Initializing provider plugins...",
   519  	))
   520  
   521  	missing := c.missingPlugins(available, requirements)
   522  
   523  	if c.getPlugins {
   524  		if len(missing) > 0 {
   525  			c.Ui.Output("- Checking for available provider plugins...")
   526  		}
   527  
   528  		for provider, reqd := range missing {
   529  			pty := addrs.NewLegacyProvider(provider)
   530  			_, providerDiags, err := c.providerInstaller.Get(pty, reqd.Versions)
   531  			diags = diags.Append(providerDiags)
   532  
   533  			if err != nil {
   534  				constraint := reqd.Versions.String()
   535  				if constraint == "" {
   536  					constraint = "(any version)"
   537  				}
   538  
   539  				switch {
   540  				case err == discovery.ErrorServiceUnreachable, err == discovery.ErrorPublicRegistryUnreachable:
   541  					c.Ui.Error(errDiscoveryServiceUnreachable)
   542  				case err == discovery.ErrorNoSuchProvider:
   543  					c.Ui.Error(fmt.Sprintf(errProviderNotFound, provider, DefaultPluginVendorDir))
   544  				case err == discovery.ErrorNoSuitableVersion:
   545  					if reqd.Versions.Unconstrained() {
   546  						// This should never happen, but might crop up if we catch
   547  						// the releases server in a weird state where the provider's
   548  						// directory is present but does not yet contain any
   549  						// versions. We'll treat it like ErrorNoSuchProvider, then.
   550  						c.Ui.Error(fmt.Sprintf(errProviderNotFound, provider, DefaultPluginVendorDir))
   551  					} else {
   552  						c.Ui.Error(fmt.Sprintf(errProviderVersionsUnsuitable, provider, reqd.Versions))
   553  					}
   554  				case errwrap.Contains(err, discovery.ErrorVersionIncompatible.Error()):
   555  					// Attempt to fetch nested error to display to the user which versions
   556  					// we considered and which versions might be compatible. Otherwise,
   557  					// we'll just display a generic version incompatible msg
   558  					incompatErr := errwrap.GetType(err, fmt.Errorf(""))
   559  					if incompatErr != nil {
   560  						c.Ui.Error(incompatErr.Error())
   561  					} else {
   562  						// Generic version incompatible msg
   563  						c.Ui.Error(fmt.Sprintf(errProviderIncompatible, provider, constraint))
   564  					}
   565  					// Reset nested errors
   566  					err = discovery.ErrorVersionIncompatible
   567  				case err == discovery.ErrorNoVersionCompatible:
   568  					// Generic version incompatible msg
   569  					c.Ui.Error(fmt.Sprintf(errProviderIncompatible, provider, constraint))
   570  				case err == discovery.ErrorSignatureVerification:
   571  					c.Ui.Error(fmt.Sprintf(errSignatureVerification, provider))
   572  				case err == discovery.ErrorChecksumVerification,
   573  					err == discovery.ErrorMissingChecksumVerification:
   574  					c.Ui.Error(fmt.Sprintf(errChecksumVerification, provider))
   575  				default:
   576  					c.Ui.Error(fmt.Sprintf(errProviderInstallError, provider, err.Error(), DefaultPluginVendorDir))
   577  				}
   578  
   579  				diags = diags.Append(err)
   580  			}
   581  		}
   582  
   583  		if diags.HasErrors() {
   584  			return true, diags
   585  		}
   586  	} else if len(missing) > 0 {
   587  		// we have missing providers, but aren't going to try and download them
   588  		var lines []string
   589  		for provider, reqd := range missing {
   590  			if reqd.Versions.Unconstrained() {
   591  				lines = append(lines, fmt.Sprintf("* %s (any version)\n", provider))
   592  			} else {
   593  				lines = append(lines, fmt.Sprintf("* %s (%s)\n", provider, reqd.Versions))
   594  			}
   595  			diags = diags.Append(fmt.Errorf("missing provider %q", provider))
   596  		}
   597  		sort.Strings(lines)
   598  		c.Ui.Error(fmt.Sprintf(errMissingProvidersNoInstall, strings.Join(lines, ""), DefaultPluginVendorDir))
   599  		return true, diags
   600  	}
   601  
   602  	// With all the providers downloaded, we'll generate our lock file
   603  	// that ensures the provider binaries remain unchanged until we init
   604  	// again. If anything changes, other commands that use providers will
   605  	// fail with an error instructing the user to re-run this command.
   606  	available = c.providerPluginSet() // re-discover to see newly-installed plugins
   607  
   608  	// internal and unmanaged providers were already filtered out, since we don't need to get them.
   609  	chosen := chooseProviders(available, nil, nil, requirements)
   610  
   611  	digests := map[string][]byte{}
   612  	for name, meta := range chosen {
   613  		digest, err := meta.SHA256()
   614  		if err != nil {
   615  			diags = diags.Append(fmt.Errorf("Failed to read provider plugin %s: %s", meta.Path, err))
   616  			return true, diags
   617  		}
   618  		digests[name] = digest
   619  		if c.ignorePluginChecksum {
   620  			digests[name] = nil
   621  		}
   622  	}
   623  	err := c.providerPluginsLock().Write(digests)
   624  	if err != nil {
   625  		diags = diags.Append(fmt.Errorf("failed to save provider manifest: %s", err))
   626  		return true, diags
   627  	}
   628  
   629  	{
   630  		// Purge any auto-installed plugins that aren't being used.
   631  		purged, err := c.providerInstaller.PurgeUnused(chosen)
   632  		if err != nil {
   633  			// Failure to purge old plugins is not a fatal error
   634  			c.Ui.Warn(fmt.Sprintf("failed to purge unused plugins: %s", err))
   635  		}
   636  		if purged != nil {
   637  			for meta := range purged {
   638  				log.Printf("[DEBUG] Purged unused %s plugin %s", meta.Name, meta.Path)
   639  			}
   640  		}
   641  	}
   642  
   643  	// If any providers have "floating" versions (completely unconstrained)
   644  	// we'll suggest the user constrain with a pessimistic constraint to
   645  	// avoid implicitly adopting a later major release.
   646  	constraintSuggestions := make(map[string]discovery.ConstraintStr)
   647  	for name, meta := range chosen {
   648  		req := requirements[name]
   649  		if req == nil {
   650  			// should never happen, but we don't want to crash here, so we'll
   651  			// be cautious.
   652  			continue
   653  		}
   654  
   655  		if req.Versions.Unconstrained() && meta.Version != discovery.VersionZero {
   656  			// meta.Version.MustParse is safe here because our "chosen" metas
   657  			// were already filtered for validity of versions.
   658  			constraintSuggestions[name] = meta.Version.MustParse().MinorUpgradeConstraintStr()
   659  		}
   660  	}
   661  	if len(constraintSuggestions) != 0 {
   662  		names := make([]string, 0, len(constraintSuggestions))
   663  		for name := range constraintSuggestions {
   664  			names = append(names, name)
   665  		}
   666  		sort.Strings(names)
   667  
   668  		c.Ui.Output(outputInitProvidersUnconstrained)
   669  		for _, name := range names {
   670  			c.Ui.Output(fmt.Sprintf("* provider.%s: version = %q", name, constraintSuggestions[name]))
   671  		}
   672  	}
   673  
   674  	return true, diags
   675  }
   676  
   677  // backendConfigOverrideBody interprets the raw values of -backend-config
   678  // arguments into a hcl Body that should override the backend settings given
   679  // in the configuration.
   680  //
   681  // If the result is nil then no override needs to be provided.
   682  //
   683  // If the returned diagnostics contains errors then the returned body may be
   684  // incomplete or invalid.
   685  func (c *InitCommand) backendConfigOverrideBody(flags rawFlags, schema *configschema.Block) (hcl.Body, tfdiags.Diagnostics) {
   686  	items := flags.AllItems()
   687  	if len(items) == 0 {
   688  		return nil, nil
   689  	}
   690  
   691  	var ret hcl.Body
   692  	var diags tfdiags.Diagnostics
   693  	synthVals := make(map[string]cty.Value)
   694  
   695  	mergeBody := func(newBody hcl.Body) {
   696  		if ret == nil {
   697  			ret = newBody
   698  		} else {
   699  			ret = configs.MergeBodies(ret, newBody)
   700  		}
   701  	}
   702  	flushVals := func() {
   703  		if len(synthVals) == 0 {
   704  			return
   705  		}
   706  		newBody := configs.SynthBody("-backend-config=...", synthVals)
   707  		mergeBody(newBody)
   708  		synthVals = make(map[string]cty.Value)
   709  	}
   710  
   711  	if len(items) == 1 && items[0].Value == "" {
   712  		// Explicitly remove all -backend-config options.
   713  		// We do this by setting an empty but non-nil ConfigOverrides.
   714  		return configs.SynthBody("-backend-config=''", synthVals), diags
   715  	}
   716  
   717  	for _, item := range items {
   718  		eq := strings.Index(item.Value, "=")
   719  
   720  		if eq == -1 {
   721  			// The value is interpreted as a filename.
   722  			newBody, fileDiags := c.loadHCLFile(item.Value)
   723  			diags = diags.Append(fileDiags)
   724  			flushVals() // deal with any accumulated individual values first
   725  			mergeBody(newBody)
   726  		} else {
   727  			name := item.Value[:eq]
   728  			rawValue := item.Value[eq+1:]
   729  			attrS := schema.Attributes[name]
   730  			if attrS == nil {
   731  				diags = diags.Append(tfdiags.Sourceless(
   732  					tfdiags.Error,
   733  					"Invalid backend configuration argument",
   734  					fmt.Sprintf("The backend configuration argument %q given on the command line is not expected for the selected backend type.", name),
   735  				))
   736  				continue
   737  			}
   738  			value, valueDiags := configValueFromCLI(item.String(), rawValue, attrS.Type)
   739  			diags = diags.Append(valueDiags)
   740  			if valueDiags.HasErrors() {
   741  				continue
   742  			}
   743  			synthVals[name] = value
   744  		}
   745  	}
   746  
   747  	flushVals()
   748  
   749  	return ret, diags
   750  }
   751  
   752  func (c *InitCommand) AutocompleteArgs() complete.Predictor {
   753  	return complete.PredictDirs("")
   754  }
   755  
   756  func (c *InitCommand) AutocompleteFlags() complete.Flags {
   757  	return complete.Flags{
   758  		"-backend":        completePredictBoolean,
   759  		"-backend-config": complete.PredictFiles("*.tfvars"), // can also be key=value, but we can't "predict" that
   760  		"-force-copy":     complete.PredictNothing,
   761  		"-from-module":    completePredictModuleSource,
   762  		"-get":            completePredictBoolean,
   763  		"-get-plugins":    completePredictBoolean,
   764  		"-input":          completePredictBoolean,
   765  		"-lock":           completePredictBoolean,
   766  		"-lock-timeout":   complete.PredictAnything,
   767  		"-no-color":       complete.PredictNothing,
   768  		"-plugin-dir":     complete.PredictDirs(""),
   769  		"-reconfigure":    complete.PredictNothing,
   770  		"-upgrade":        completePredictBoolean,
   771  		"-verify-plugins": completePredictBoolean,
   772  	}
   773  }
   774  
   775  func (c *InitCommand) Help() string {
   776  	helpText := `
   777  Usage: terraform init [options] [DIR]
   778  
   779    Initialize a new or existing Terraform working directory by creating
   780    initial files, loading any remote state, downloading modules, etc.
   781  
   782    This is the first command that should be run for any new or existing
   783    Terraform configuration per machine. This sets up all the local data
   784    necessary to run Terraform that is typically not committed to version
   785    control.
   786  
   787    This command is always safe to run multiple times. Though subsequent runs
   788    may give errors, this command will never delete your configuration or
   789    state. Even so, if you have important information, please back it up prior
   790    to running this command, just in case.
   791  
   792    If no arguments are given, the configuration in this working directory
   793    is initialized.
   794  
   795  Options:
   796  
   797    -backend=true        Configure the backend for this configuration.
   798  
   799    -backend-config=path This can be either a path to an HCL file with key/value
   800                         assignments (same format as terraform.tfvars) or a
   801                         'key=value' format. This is merged with what is in the
   802                         configuration file. This can be specified multiple
   803                         times. The backend type must be in the configuration
   804                         itself.
   805  
   806    -force-copy          Suppress prompts about copying state data. This is
   807                         equivalent to providing a "yes" to all confirmation
   808                         prompts.
   809  
   810    -from-module=SOURCE  Copy the contents of the given module into the target
   811                         directory before initialization.
   812  
   813    -get=true            Download any modules for this configuration.
   814  
   815    -get-plugins=true    Download any missing plugins for this configuration.
   816  
   817    -input=true          Ask for input if necessary. If false, will error if
   818                         input was required.
   819  
   820    -lock=true           Lock the state file when locking is supported.
   821  
   822    -lock-timeout=0s     Duration to retry a state lock.
   823  
   824    -no-color            If specified, output won't contain any color.
   825  
   826    -plugin-dir          Directory containing plugin binaries. This overrides all
   827                         default search paths for plugins, and prevents the 
   828                         automatic installation of plugins. This flag can be used
   829                         multiple times.
   830  
   831    -reconfigure         Reconfigure the backend, ignoring any saved
   832                         configuration.
   833  
   834    -upgrade=false       If installing modules (-get) or plugins (-get-plugins),
   835                         ignore previously-downloaded objects and install the
   836                         latest version allowed within configured constraints.
   837  
   838    -verify-plugins=true Verify the authenticity and integrity of automatically
   839                         downloaded plugins.
   840  `
   841  	return strings.TrimSpace(helpText)
   842  }
   843  
   844  func (c *InitCommand) Synopsis() string {
   845  	return "Initialize a Terraform working directory"
   846  }
   847  
   848  const errInitConfigError = `
   849  There are some problems with the configuration, described below.
   850  
   851  The Terraform configuration must be valid before initialization so that
   852  Terraform can determine which modules and providers need to be installed.
   853  `
   854  
   855  const errInitCopyNotEmpty = `
   856  The working directory already contains files. The -from-module option requires
   857  an empty directory into which a copy of the referenced module will be placed.
   858  
   859  To initialize the configuration already in this working directory, omit the
   860  -from-module option.
   861  `
   862  
   863  const outputInitEmpty = `
   864  [reset][bold]Terraform initialized in an empty directory![reset]
   865  
   866  The directory has no Terraform configuration files. You may begin working
   867  with Terraform immediately by creating Terraform configuration files.
   868  `
   869  
   870  const outputInitSuccess = `
   871  [reset][bold][green]Terraform has been successfully initialized![reset][green]
   872  `
   873  
   874  const outputInitSuccessCLI = `[reset][green]
   875  You may now begin working with Terraform. Try running "terraform plan" to see
   876  any changes that are required for your infrastructure. All Terraform commands
   877  should now work.
   878  
   879  If you ever set or change modules or backend configuration for Terraform,
   880  rerun this command to reinitialize your working directory. If you forget, other
   881  commands will detect it and remind you to do so if necessary.
   882  `
   883  
   884  const outputInitSuccessConfigUpgrade = `
   885  [reset][bold]Terraform has initialized, but configuration upgrades may be needed.[reset]
   886  
   887  Terraform found syntax errors in the configuration that prevented full
   888  initialization. If you've recently upgraded to Terraform v0.12, this may be
   889  because your configuration uses syntax constructs that are no longer valid,
   890  and so must be updated before full initialization is possible.
   891  
   892  Run terraform init for this configuration at a shell prompt for more information
   893  on how to update it for Terraform v0.12 compatibility.
   894  `
   895  
   896  const outputInitSuccessConfigUpgradeCLI = `[reset][green]
   897  [reset][bold]Terraform has initialized, but configuration upgrades may be needed.[reset]
   898  
   899  Terraform found syntax errors in the configuration that prevented full
   900  initialization. If you've recently upgraded to Terraform v0.12, this may be
   901  because your configuration uses syntax constructs that are no longer valid,
   902  and so must be updated before full initialization is possible.
   903  
   904  Terraform has installed the required providers to support the configuration
   905  upgrade process. To begin upgrading your configuration, run the following:
   906      terraform 0.12upgrade
   907  
   908  To see the full set of errors that led to this message, run:
   909      terraform validate
   910  `
   911  
   912  const outputInitProvidersUnconstrained = `
   913  The following providers do not have any version constraints in configuration,
   914  so the latest version was installed.
   915  
   916  To prevent automatic upgrades to new major versions that may contain breaking
   917  changes, it is recommended to add version = "..." constraints to the
   918  corresponding provider blocks in configuration, with the constraint strings
   919  suggested below.
   920  `
   921  
   922  const errDiscoveryServiceUnreachable = `
   923  [reset][bold][red]Registry service unreachable.[reset][red]
   924  
   925  This may indicate a network issue, or an issue with the requested Terraform Registry.
   926  `
   927  
   928  const errProviderNotFound = `
   929  [reset][bold][red]Provider %[1]q not available for installation.[reset][red]
   930  
   931  A provider named %[1]q could not be found in the Terraform Registry.
   932  
   933  This may result from mistyping the provider name, or the given provider may
   934  be a third-party provider that cannot be installed automatically.
   935  
   936  In the latter case, the plugin must be installed manually by locating and
   937  downloading a suitable distribution package and placing the plugin's executable
   938  file in the following directory:
   939      %[2]s
   940  
   941  Terraform detects necessary plugins by inspecting the configuration and state.
   942  To view the provider versions requested by each module, run
   943  "terraform providers".
   944  `
   945  
   946  const errProviderVersionsUnsuitable = `
   947  [reset][bold][red]No provider %[1]q plugins meet the constraint %[2]q.[reset][red]
   948  
   949  The version constraint is derived from the "version" argument within the
   950  provider %[1]q block in configuration. Child modules may also apply
   951  provider version constraints. To view the provider versions requested by each
   952  module in the current configuration, run "terraform providers".
   953  
   954  To proceed, the version constraints for this provider must be relaxed by
   955  either adjusting or removing the "version" argument in the provider blocks
   956  throughout the configuration.
   957  `
   958  
   959  const errProviderIncompatible = `
   960  [reset][bold][red]No available provider %[1]q plugins are compatible with this Terraform version.[reset][red]
   961  
   962  From time to time, new Terraform major releases can change the requirements for
   963  plugins such that older plugins become incompatible.
   964  
   965  Terraform checked all of the plugin versions matching the given constraint:
   966      %[2]s
   967  
   968  Unfortunately, none of the suitable versions are compatible with this version
   969  of Terraform. If you have recently upgraded Terraform, it may be necessary to
   970  move to a newer major release of this provider. Alternatively, if you are
   971  attempting to upgrade the provider to a new major version you may need to
   972  also upgrade Terraform to support the new version.
   973  
   974  Consult the documentation for this provider for more information on
   975  compatibility between provider versions and Terraform versions.
   976  `
   977  
   978  const errProviderInstallError = `
   979  [reset][bold][red]Error installing provider %[1]q: %[2]s.[reset][red]
   980  
   981  Terraform analyses the configuration and state and automatically downloads
   982  plugins for the providers used. However, when attempting to download this
   983  plugin an unexpected error occurred.
   984  
   985  This may be caused if for some reason Terraform is unable to reach the
   986  plugin repository. The repository may be unreachable if access is blocked
   987  by a firewall.
   988  
   989  If automatic installation is not possible or desirable in your environment,
   990  you may alternatively manually install plugins by downloading a suitable
   991  distribution package and placing the plugin's executable file in the
   992  following directory:
   993      %[3]s
   994  `
   995  
   996  const errMissingProvidersNoInstall = `
   997  [reset][bold][red]Missing required providers.[reset][red]
   998  
   999  The following provider constraints are not met by the currently-installed
  1000  provider plugins:
  1001  
  1002  %[1]s
  1003  Terraform can automatically download and install plugins to meet the given
  1004  constraints, but this step was skipped due to the use of -get-plugins=false
  1005  and/or -plugin-dir on the command line.
  1006  
  1007  If automatic installation is not possible or desirable in your environment,
  1008  you may manually install plugins by downloading a suitable distribution package
  1009  and placing the plugin's executable file in one of the directories given in
  1010  by -plugin-dir on the command line, or in the following directory if custom
  1011  plugin directories are not set:
  1012      %[2]s
  1013  `
  1014  
  1015  const errChecksumVerification = `
  1016  [reset][bold][red]Error verifying checksum for provider %[1]q[reset][red]
  1017  The checksum for provider distribution from the Terraform Registry
  1018  did not match the source. This may mean that the distributed files
  1019  were changed after this version was released to the Registry.
  1020  `
  1021  
  1022  const errSignatureVerification = `
  1023  [reset][bold][red]Error verifying GPG signature for provider %[1]q[reset][red]
  1024  Terraform was unable to verify the GPG signature of the downloaded provider
  1025  files using the keys downloaded from the Terraform Registry. This may mean that
  1026  the publisher of the provider removed the key it was signed with, or that the
  1027  distributed files were changed after this version was released.
  1028  `