github.com/ben-turner/terraform@v0.11.8-0.20180503104400-0cc9e050ecd4/command/init.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/posener/complete"
    11  
    12  	multierror "github.com/hashicorp/go-multierror"
    13  	"github.com/hashicorp/terraform/backend"
    14  	"github.com/hashicorp/terraform/config"
    15  	"github.com/hashicorp/terraform/config/module"
    16  	"github.com/hashicorp/terraform/helper/variables"
    17  	"github.com/hashicorp/terraform/plugin"
    18  	"github.com/hashicorp/terraform/plugin/discovery"
    19  	"github.com/hashicorp/terraform/terraform"
    20  )
    21  
    22  // InitCommand is a Command implementation that takes a Terraform
    23  // module and clones it to the working directory.
    24  type InitCommand struct {
    25  	Meta
    26  
    27  	// getPlugins is for the -get-plugins flag
    28  	getPlugins bool
    29  
    30  	// providerInstaller is used to download and install providers that
    31  	// aren't found locally. This uses a discovery.ProviderInstaller instance
    32  	// by default, but it can be overridden here as a way to mock fetching
    33  	// providers for tests.
    34  	providerInstaller discovery.Installer
    35  }
    36  
    37  func (c *InitCommand) Run(args []string) int {
    38  	var flagFromModule string
    39  	var flagBackend, flagGet, flagUpgrade bool
    40  	var flagConfigExtra map[string]interface{}
    41  	var flagPluginPath FlagStringSlice
    42  	var flagVerifyPlugins bool
    43  
    44  	args, err := c.Meta.process(args, false)
    45  	if err != nil {
    46  		return 1
    47  	}
    48  	cmdFlags := c.flagSet("init")
    49  	cmdFlags.BoolVar(&flagBackend, "backend", true, "")
    50  	cmdFlags.Var((*variables.FlagAny)(&flagConfigExtra), "backend-config", "")
    51  	cmdFlags.StringVar(&flagFromModule, "from-module", "", "copy the source of the given module into the directory before init")
    52  	cmdFlags.BoolVar(&flagGet, "get", true, "")
    53  	cmdFlags.BoolVar(&c.getPlugins, "get-plugins", true, "")
    54  	cmdFlags.BoolVar(&c.forceInitCopy, "force-copy", false, "suppress prompts about copying state data")
    55  	cmdFlags.BoolVar(&c.Meta.stateLock, "lock", true, "lock state")
    56  	cmdFlags.DurationVar(&c.Meta.stateLockTimeout, "lock-timeout", 0, "lock timeout")
    57  	cmdFlags.BoolVar(&c.reconfigure, "reconfigure", false, "reconfigure")
    58  	cmdFlags.BoolVar(&flagUpgrade, "upgrade", false, "")
    59  	cmdFlags.Var(&flagPluginPath, "plugin-dir", "plugin directory")
    60  	cmdFlags.BoolVar(&flagVerifyPlugins, "verify-plugins", true, "verify plugins")
    61  
    62  	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
    63  	if err := cmdFlags.Parse(args); err != nil {
    64  		return 1
    65  	}
    66  
    67  	if len(flagPluginPath) > 0 {
    68  		c.pluginPath = flagPluginPath
    69  		c.getPlugins = false
    70  	}
    71  
    72  	// set providerInstaller if we don't have a test version already
    73  	if c.providerInstaller == nil {
    74  		c.providerInstaller = &discovery.ProviderInstaller{
    75  			Dir:   c.pluginDir(),
    76  			Cache: c.pluginCache(),
    77  			PluginProtocolVersion: plugin.Handshake.ProtocolVersion,
    78  			SkipVerify:            !flagVerifyPlugins,
    79  			Ui:                    c.Ui,
    80  		}
    81  	}
    82  
    83  	// Validate the arg count
    84  	args = cmdFlags.Args()
    85  	if len(args) > 1 {
    86  		c.Ui.Error("The init command expects at most one argument.\n")
    87  		cmdFlags.Usage()
    88  		return 1
    89  	}
    90  
    91  	if err := c.storePluginPath(c.pluginPath); err != nil {
    92  		c.Ui.Error(fmt.Sprintf("Error saving -plugin-path values: %s", err))
    93  		return 1
    94  	}
    95  
    96  	// Get our pwd. We don't always need it but always getting it is easier
    97  	// than the logic to determine if it is or isn't needed.
    98  	pwd, err := os.Getwd()
    99  	if err != nil {
   100  		c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
   101  		return 1
   102  	}
   103  
   104  	// If an argument is provided then it overrides our working directory.
   105  	path := pwd
   106  	if len(args) == 1 {
   107  		path = args[0]
   108  	}
   109  
   110  	// This will track whether we outputted anything so that we know whether
   111  	// to output a newline before the success message
   112  	var header bool
   113  
   114  	if flagFromModule != "" {
   115  		src := flagFromModule
   116  
   117  		empty, err := config.IsEmptyDir(path)
   118  		if err != nil {
   119  			c.Ui.Error(fmt.Sprintf("Error validating destination directory: %s", err))
   120  			return 1
   121  		}
   122  		if !empty {
   123  			c.Ui.Error(strings.TrimSpace(errInitCopyNotEmpty))
   124  			return 1
   125  		}
   126  
   127  		c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
   128  			"[reset][bold]Copying configuration[reset] from %q...", src,
   129  		)))
   130  		header = true
   131  
   132  		s := module.NewStorage("", c.Services, c.Credentials)
   133  		if err := s.GetModule(path, src); err != nil {
   134  			c.Ui.Error(fmt.Sprintf("Error copying source module: %s", err))
   135  			return 1
   136  		}
   137  	}
   138  
   139  	// If our directory is empty, then we're done. We can't get or setup
   140  	// the backend with an empty directory.
   141  	if empty, err := config.IsEmptyDir(path); err != nil {
   142  		c.Ui.Error(fmt.Sprintf(
   143  			"Error checking configuration: %s", err))
   144  		return 1
   145  	} else if empty {
   146  		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitEmpty)))
   147  		return 0
   148  	}
   149  
   150  	var back backend.Backend
   151  
   152  	// If we're performing a get or loading the backend, then we perform
   153  	// some extra tasks.
   154  	if flagGet || flagBackend {
   155  		conf, err := c.Config(path)
   156  		if err != nil {
   157  			// Since this may be the user's first ever interaction with Terraform,
   158  			// we'll provide some additional context in this case.
   159  			c.Ui.Error(strings.TrimSpace(errInitConfigError))
   160  			c.showDiagnostics(err)
   161  			return 1
   162  		}
   163  
   164  		// If we requested downloading modules and have modules in the config
   165  		if flagGet && len(conf.Modules) > 0 {
   166  			header = true
   167  
   168  			getMode := module.GetModeGet
   169  			if flagUpgrade {
   170  				getMode = module.GetModeUpdate
   171  				c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
   172  					"[reset][bold]Upgrading modules...")))
   173  			} else {
   174  				c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
   175  					"[reset][bold]Initializing modules...")))
   176  			}
   177  
   178  			if err := getModules(&c.Meta, path, getMode); err != nil {
   179  				c.Ui.Error(fmt.Sprintf(
   180  					"Error downloading modules: %s", err))
   181  				return 1
   182  			}
   183  		}
   184  
   185  		// If we're requesting backend configuration or looking for required
   186  		// plugins, load the backend
   187  		if flagBackend {
   188  			header = true
   189  
   190  			// Only output that we're initializing a backend if we have
   191  			// something in the config. We can be UNSETTING a backend as well
   192  			// in which case we choose not to show this.
   193  			if conf.Terraform != nil && conf.Terraform.Backend != nil {
   194  				c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
   195  					"\n[reset][bold]Initializing the backend...")))
   196  			}
   197  
   198  			opts := &BackendOpts{
   199  				Config:      conf,
   200  				ConfigExtra: flagConfigExtra,
   201  				Init:        true,
   202  			}
   203  			if back, err = c.Backend(opts); err != nil {
   204  				c.Ui.Error(err.Error())
   205  				return 1
   206  			}
   207  		}
   208  	}
   209  
   210  	if back == nil {
   211  		// If we didn't initialize a backend then we'll try to at least
   212  		// instantiate one. This might fail if it wasn't already initalized
   213  		// by a previous run, so we must still expect that "back" may be nil
   214  		// in code that follows.
   215  		back, err = c.Backend(nil)
   216  		if err != nil {
   217  			// This is fine. We'll proceed with no backend, then.
   218  			back = nil
   219  		}
   220  	}
   221  
   222  	var state *terraform.State
   223  
   224  	// If we have a functional backend (either just initialized or initialized
   225  	// on a previous run) we'll use the current state as a potential source
   226  	// of provider dependencies.
   227  	if back != nil {
   228  		sMgr, err := back.State(c.Workspace())
   229  		if err != nil {
   230  			c.Ui.Error(fmt.Sprintf(
   231  				"Error loading state: %s", err))
   232  			return 1
   233  		}
   234  
   235  		if err := sMgr.RefreshState(); err != nil {
   236  			c.Ui.Error(fmt.Sprintf(
   237  				"Error refreshing state: %s", err))
   238  			return 1
   239  		}
   240  
   241  		state = sMgr.State()
   242  	}
   243  
   244  	if v := os.Getenv(ProviderSkipVerifyEnvVar); v != "" {
   245  		c.ignorePluginChecksum = true
   246  	}
   247  
   248  	// Now that we have loaded all modules, check the module tree for missing providers.
   249  	err = c.getProviders(path, state, flagUpgrade)
   250  	if err != nil {
   251  		// this function provides its own output
   252  		log.Printf("[ERROR] %s", err)
   253  		return 1
   254  	}
   255  
   256  	// If we outputted information, then we need to output a newline
   257  	// so that our success message is nicely spaced out from prior text.
   258  	if header {
   259  		c.Ui.Output("")
   260  	}
   261  
   262  	c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccess)))
   263  	if !c.RunningInAutomation {
   264  		// If we're not running in an automation wrapper, give the user
   265  		// some more detailed next steps that are appropriate for interactive
   266  		// shell usage.
   267  		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccessCLI)))
   268  	}
   269  
   270  	return 0
   271  }
   272  
   273  // Load the complete module tree, and fetch any missing providers.
   274  // This method outputs its own Ui.
   275  func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade bool) error {
   276  	mod, diags := c.Module(path)
   277  	if diags.HasErrors() {
   278  		c.showDiagnostics(diags)
   279  		return diags.Err()
   280  	}
   281  
   282  	if err := terraform.CheckStateVersion(state); err != nil {
   283  		diags = diags.Append(err)
   284  		c.showDiagnostics(diags)
   285  		return err
   286  	}
   287  
   288  	if err := terraform.CheckRequiredVersion(mod); err != nil {
   289  		diags = diags.Append(err)
   290  		c.showDiagnostics(diags)
   291  		return err
   292  	}
   293  
   294  	var available discovery.PluginMetaSet
   295  	if upgrade {
   296  		// If we're in upgrade mode, we ignore any auto-installed plugins
   297  		// in "available", causing us to reinstall and possibly upgrade them.
   298  		available = c.providerPluginManuallyInstalledSet()
   299  	} else {
   300  		available = c.providerPluginSet()
   301  	}
   302  
   303  	requirements := terraform.ModuleTreeDependencies(mod, state).AllPluginRequirements()
   304  	if len(requirements) == 0 {
   305  		// nothing to initialize
   306  		return nil
   307  	}
   308  
   309  	c.Ui.Output(c.Colorize().Color(
   310  		"\n[reset][bold]Initializing provider plugins...",
   311  	))
   312  
   313  	missing := c.missingPlugins(available, requirements)
   314  
   315  	var errs error
   316  	if c.getPlugins {
   317  		if len(missing) > 0 {
   318  			c.Ui.Output(fmt.Sprintf("- Checking for available provider plugins on %s...",
   319  				discovery.GetReleaseHost()))
   320  		}
   321  
   322  		for provider, reqd := range missing {
   323  			_, err := c.providerInstaller.Get(provider, reqd.Versions)
   324  
   325  			if err != nil {
   326  				switch err {
   327  				case discovery.ErrorNoSuchProvider:
   328  					c.Ui.Error(fmt.Sprintf(errProviderNotFound, provider, DefaultPluginVendorDir))
   329  				case discovery.ErrorNoSuitableVersion:
   330  					if reqd.Versions.Unconstrained() {
   331  						// This should never happen, but might crop up if we catch
   332  						// the releases server in a weird state where the provider's
   333  						// directory is present but does not yet contain any
   334  						// versions. We'll treat it like ErrorNoSuchProvider, then.
   335  						c.Ui.Error(fmt.Sprintf(errProviderNotFound, provider, DefaultPluginVendorDir))
   336  					} else {
   337  						c.Ui.Error(fmt.Sprintf(errProviderVersionsUnsuitable, provider, reqd.Versions))
   338  					}
   339  				case discovery.ErrorNoVersionCompatible:
   340  					// FIXME: This error message is sub-awesome because we don't
   341  					// have enough information here to tell the user which versions
   342  					// we considered and which versions might be compatible.
   343  					constraint := reqd.Versions.String()
   344  					if constraint == "" {
   345  						constraint = "(any version)"
   346  					}
   347  					c.Ui.Error(fmt.Sprintf(errProviderIncompatible, provider, constraint))
   348  				default:
   349  					c.Ui.Error(fmt.Sprintf(errProviderInstallError, provider, err.Error(), DefaultPluginVendorDir))
   350  				}
   351  
   352  				errs = multierror.Append(errs, err)
   353  			}
   354  		}
   355  
   356  		if errs != nil {
   357  			return errs
   358  		}
   359  	} else if len(missing) > 0 {
   360  		// we have missing providers, but aren't going to try and download them
   361  		var lines []string
   362  		for provider, reqd := range missing {
   363  			if reqd.Versions.Unconstrained() {
   364  				lines = append(lines, fmt.Sprintf("* %s (any version)\n", provider))
   365  			} else {
   366  				lines = append(lines, fmt.Sprintf("* %s (%s)\n", provider, reqd.Versions))
   367  			}
   368  			errs = multierror.Append(errs, fmt.Errorf("missing provider %q", provider))
   369  		}
   370  		sort.Strings(lines)
   371  		c.Ui.Error(fmt.Sprintf(errMissingProvidersNoInstall, strings.Join(lines, ""), DefaultPluginVendorDir))
   372  		return errs
   373  	}
   374  
   375  	// With all the providers downloaded, we'll generate our lock file
   376  	// that ensures the provider binaries remain unchanged until we init
   377  	// again. If anything changes, other commands that use providers will
   378  	// fail with an error instructing the user to re-run this command.
   379  	available = c.providerPluginSet() // re-discover to see newly-installed plugins
   380  
   381  	// internal providers were already filtered out, since we don't need to get them.
   382  	chosen := choosePlugins(available, nil, requirements)
   383  
   384  	digests := map[string][]byte{}
   385  	for name, meta := range chosen {
   386  		digest, err := meta.SHA256()
   387  		if err != nil {
   388  			c.Ui.Error(fmt.Sprintf("failed to read provider plugin %s: %s", meta.Path, err))
   389  			return err
   390  		}
   391  		digests[name] = digest
   392  		if c.ignorePluginChecksum {
   393  			digests[name] = nil
   394  		}
   395  	}
   396  	err := c.providerPluginsLock().Write(digests)
   397  	if err != nil {
   398  		c.Ui.Error(fmt.Sprintf("failed to save provider manifest: %s", err))
   399  		return err
   400  	}
   401  
   402  	{
   403  		// Purge any auto-installed plugins that aren't being used.
   404  		purged, err := c.providerInstaller.PurgeUnused(chosen)
   405  		if err != nil {
   406  			// Failure to purge old plugins is not a fatal error
   407  			c.Ui.Warn(fmt.Sprintf("failed to purge unused plugins: %s", err))
   408  		}
   409  		if purged != nil {
   410  			for meta := range purged {
   411  				log.Printf("[DEBUG] Purged unused %s plugin %s", meta.Name, meta.Path)
   412  			}
   413  		}
   414  	}
   415  
   416  	// If any providers have "floating" versions (completely unconstrained)
   417  	// we'll suggest the user constrain with a pessimistic constraint to
   418  	// avoid implicitly adopting a later major release.
   419  	constraintSuggestions := make(map[string]discovery.ConstraintStr)
   420  	for name, meta := range chosen {
   421  		req := requirements[name]
   422  		if req == nil {
   423  			// should never happen, but we don't want to crash here, so we'll
   424  			// be cautious.
   425  			continue
   426  		}
   427  
   428  		if req.Versions.Unconstrained() && meta.Version != discovery.VersionZero {
   429  			// meta.Version.MustParse is safe here because our "chosen" metas
   430  			// were already filtered for validity of versions.
   431  			constraintSuggestions[name] = meta.Version.MustParse().MinorUpgradeConstraintStr()
   432  		}
   433  	}
   434  	if len(constraintSuggestions) != 0 {
   435  		names := make([]string, 0, len(constraintSuggestions))
   436  		for name := range constraintSuggestions {
   437  			names = append(names, name)
   438  		}
   439  		sort.Strings(names)
   440  
   441  		c.Ui.Output(outputInitProvidersUnconstrained)
   442  		for _, name := range names {
   443  			c.Ui.Output(fmt.Sprintf("* provider.%s: version = %q", name, constraintSuggestions[name]))
   444  		}
   445  	}
   446  
   447  	return nil
   448  }
   449  
   450  func (c *InitCommand) AutocompleteArgs() complete.Predictor {
   451  	return complete.PredictDirs("")
   452  }
   453  
   454  func (c *InitCommand) AutocompleteFlags() complete.Flags {
   455  	return complete.Flags{
   456  		"-backend":        completePredictBoolean,
   457  		"-backend-config": complete.PredictFiles("*.tfvars"), // can also be key=value, but we can't "predict" that
   458  		"-force-copy":     complete.PredictNothing,
   459  		"-from-module":    completePredictModuleSource,
   460  		"-get":            completePredictBoolean,
   461  		"-get-plugins":    completePredictBoolean,
   462  		"-input":          completePredictBoolean,
   463  		"-lock":           completePredictBoolean,
   464  		"-lock-timeout":   complete.PredictAnything,
   465  		"-no-color":       complete.PredictNothing,
   466  		"-plugin-dir":     complete.PredictDirs(""),
   467  		"-reconfigure":    complete.PredictNothing,
   468  		"-upgrade":        completePredictBoolean,
   469  		"-verify-plugins": completePredictBoolean,
   470  	}
   471  }
   472  
   473  func (c *InitCommand) Help() string {
   474  	helpText := `
   475  Usage: terraform init [options] [DIR]
   476  
   477    Initialize a new or existing Terraform working directory by creating
   478    initial files, loading any remote state, downloading modules, etc.
   479  
   480    This is the first command that should be run for any new or existing
   481    Terraform configuration per machine. This sets up all the local data
   482    necessary to run Terraform that is typically not committed to version
   483    control.
   484  
   485    This command is always safe to run multiple times. Though subsequent runs
   486    may give errors, this command will never delete your configuration or
   487    state. Even so, if you have important information, please back it up prior
   488    to running this command, just in case.
   489  
   490    If no arguments are given, the configuration in this working directory
   491    is initialized.
   492  
   493  Options:
   494  
   495    -backend=true        Configure the backend for this configuration.
   496  
   497    -backend-config=path This can be either a path to an HCL file with key/value
   498                         assignments (same format as terraform.tfvars) or a
   499                         'key=value' format. This is merged with what is in the
   500                         configuration file. This can be specified multiple
   501                         times. The backend type must be in the configuration
   502                         itself.
   503  
   504    -force-copy          Suppress prompts about copying state data. This is
   505                         equivalent to providing a "yes" to all confirmation
   506                         prompts.
   507  
   508    -from-module=SOURCE  Copy the contents of the given module into the target
   509                         directory before initialization.
   510  
   511    -get=true            Download any modules for this configuration.
   512  
   513    -get-plugins=true    Download any missing plugins for this configuration.
   514  
   515    -input=true          Ask for input if necessary. If false, will error if
   516                         input was required.
   517  
   518    -lock=true           Lock the state file when locking is supported.
   519  
   520    -lock-timeout=0s     Duration to retry a state lock.
   521  
   522    -no-color            If specified, output won't contain any color.
   523  
   524    -plugin-dir          Directory containing plugin binaries. This overrides all
   525                         default search paths for plugins, and prevents the 
   526                         automatic installation of plugins. This flag can be used
   527                         multiple times.
   528  
   529    -reconfigure         Reconfigure the backend, ignoring any saved
   530                         configuration.
   531  
   532    -upgrade=false       If installing modules (-get) or plugins (-get-plugins),
   533                         ignore previously-downloaded objects and install the
   534                         latest version allowed within configured constraints.
   535  
   536    -verify-plugins=true Verify the authenticity and integrity of automatically
   537                         downloaded plugins.
   538  `
   539  	return strings.TrimSpace(helpText)
   540  }
   541  
   542  func (c *InitCommand) Synopsis() string {
   543  	return "Initialize a Terraform working directory"
   544  }
   545  
   546  const errInitConfigError = `
   547  There are some problems with the configuration, described below.
   548  
   549  The Terraform configuration must be valid before initialization so that
   550  Terraform can determine which modules and providers need to be installed.
   551  `
   552  
   553  const errInitCopyNotEmpty = `
   554  The working directory already contains files. The -from-module option requires
   555  an empty directory into which a copy of the referenced module will be placed.
   556  
   557  To initialize the configuration already in this working directory, omit the
   558  -from-module option.
   559  `
   560  
   561  const outputInitEmpty = `
   562  [reset][bold]Terraform initialized in an empty directory![reset]
   563  
   564  The directory has no Terraform configuration files. You may begin working
   565  with Terraform immediately by creating Terraform configuration files.
   566  `
   567  
   568  const outputInitSuccess = `
   569  [reset][bold][green]Terraform has been successfully initialized![reset][green]
   570  `
   571  
   572  const outputInitSuccessCLI = `[reset][green]
   573  You may now begin working with Terraform. Try running "terraform plan" to see
   574  any changes that are required for your infrastructure. All Terraform commands
   575  should now work.
   576  
   577  If you ever set or change modules or backend configuration for Terraform,
   578  rerun this command to reinitialize your working directory. If you forget, other
   579  commands will detect it and remind you to do so if necessary.
   580  `
   581  
   582  const outputInitProvidersUnconstrained = `
   583  The following providers do not have any version constraints in configuration,
   584  so the latest version was installed.
   585  
   586  To prevent automatic upgrades to new major versions that may contain breaking
   587  changes, it is recommended to add version = "..." constraints to the
   588  corresponding provider blocks in configuration, with the constraint strings
   589  suggested below.
   590  `
   591  
   592  const errProviderNotFound = `
   593  [reset][bold][red]Provider %[1]q not available for installation.[reset][red]
   594  
   595  A provider named %[1]q could not be found in the official repository.
   596  
   597  This may result from mistyping the provider name, or the given provider may
   598  be a third-party provider that cannot be installed automatically.
   599  
   600  In the latter case, the plugin must be installed manually by locating and
   601  downloading a suitable distribution package and placing the plugin's executable
   602  file in the following directory:
   603      %[2]s
   604  
   605  Terraform detects necessary plugins by inspecting the configuration and state.
   606  To view the provider versions requested by each module, run
   607  "terraform providers".
   608  `
   609  
   610  const errProviderVersionsUnsuitable = `
   611  [reset][bold][red]No provider %[1]q plugins meet the constraint %[2]q.[reset][red]
   612  
   613  The version constraint is derived from the "version" argument within the
   614  provider %[1]q block in configuration. Child modules may also apply
   615  provider version constraints. To view the provider versions requested by each
   616  module in the current configuration, run "terraform providers".
   617  
   618  To proceed, the version constraints for this provider must be relaxed by
   619  either adjusting or removing the "version" argument in the provider blocks
   620  throughout the configuration.
   621  `
   622  
   623  const errProviderIncompatible = `
   624  [reset][bold][red]No available provider %[1]q plugins are compatible with this Terraform version.[reset][red]
   625  
   626  From time to time, new Terraform major releases can change the requirements for
   627  plugins such that older plugins become incompatible.
   628  
   629  Terraform checked all of the plugin versions matching the given constraint:
   630      %[2]s
   631  
   632  Unfortunately, none of the suitable versions are compatible with this version
   633  of Terraform. If you have recently upgraded Terraform, it may be necessary to
   634  move to a newer major release of this provider. Alternatively, if you are
   635  attempting to upgrade the provider to a new major version you may need to
   636  also upgrade Terraform to support the new version.
   637  
   638  Consult the documentation for this provider for more information on
   639  compatibility between provider versions and Terraform versions.
   640  `
   641  
   642  const errProviderInstallError = `
   643  [reset][bold][red]Error installing provider %[1]q: %[2]s.[reset][red]
   644  
   645  Terraform analyses the configuration and state and automatically downloads
   646  plugins for the providers used. However, when attempting to download this
   647  plugin an unexpected error occured.
   648  
   649  This may be caused if for some reason Terraform is unable to reach the
   650  plugin repository. The repository may be unreachable if access is blocked
   651  by a firewall.
   652  
   653  If automatic installation is not possible or desirable in your environment,
   654  you may alternatively manually install plugins by downloading a suitable
   655  distribution package and placing the plugin's executable file in the
   656  following directory:
   657      %[3]s
   658  `
   659  
   660  const errMissingProvidersNoInstall = `
   661  [reset][bold][red]Missing required providers.[reset][red]
   662  
   663  The following provider constraints are not met by the currently-installed
   664  provider plugins:
   665  
   666  %[1]s
   667  Terraform can automatically download and install plugins to meet the given
   668  constraints, but this step was skipped due to the use of -get-plugins=false
   669  and/or -plugin-dir on the command line.
   670  
   671  If automatic installation is not possible or desirable in your environment,
   672  you may manually install plugins by downloading a suitable distribution package
   673  and placing the plugin's executable file in one of the directories given in
   674  by -plugin-dir on the command line, or in the following directory if custom
   675  plugin directories are not set:
   676      %[2]s
   677  `