github.com/alexaandru/terraform@v0.11.1-0.20171120185746-28632790b723/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  
   186  		// If we're requesting backend configuration or looking for required
   187  		// plugins, load the backend
   188  		if flagBackend {
   189  			header = true
   190  
   191  			// Only output that we're initializing a backend if we have
   192  			// something in the config. We can be UNSETTING a backend as well
   193  			// in which case we choose not to show this.
   194  			if conf.Terraform != nil && conf.Terraform.Backend != nil {
   195  				c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
   196  					"\n[reset][bold]Initializing the backend...")))
   197  			}
   198  
   199  			opts := &BackendOpts{
   200  				Config:      conf,
   201  				ConfigExtra: flagConfigExtra,
   202  				Init:        true,
   203  			}
   204  			if back, err = c.Backend(opts); err != nil {
   205  				c.Ui.Error(err.Error())
   206  				return 1
   207  			}
   208  		}
   209  	}
   210  
   211  	if back == nil {
   212  		// If we didn't initialize a backend then we'll try to at least
   213  		// instantiate one. This might fail if it wasn't already initalized
   214  		// by a previous run, so we must still expect that "back" may be nil
   215  		// in code that follows.
   216  		back, err = c.Backend(nil)
   217  		if err != nil {
   218  			// This is fine. We'll proceed with no backend, then.
   219  			back = nil
   220  		}
   221  	}
   222  
   223  	var state *terraform.State
   224  
   225  	// If we have a functional backend (either just initialized or initialized
   226  	// on a previous run) we'll use the current state as a potential source
   227  	// of provider dependencies.
   228  	if back != nil {
   229  		sMgr, err := back.State(c.Workspace())
   230  		if err != nil {
   231  			c.Ui.Error(fmt.Sprintf(
   232  				"Error loading state: %s", err))
   233  			return 1
   234  		}
   235  
   236  		if err := sMgr.RefreshState(); err != nil {
   237  			c.Ui.Error(fmt.Sprintf(
   238  				"Error refreshing state: %s", err))
   239  			return 1
   240  		}
   241  
   242  		state = sMgr.State()
   243  	}
   244  
   245  	if v := os.Getenv(ProviderSkipVerifyEnvVar); v != "" {
   246  		c.ignorePluginChecksum = true
   247  	}
   248  
   249  	// Now that we have loaded all modules, check the module tree for missing providers.
   250  	err = c.getProviders(path, state, flagUpgrade)
   251  	if err != nil {
   252  		// this function provides its own output
   253  		log.Printf("[ERROR] %s", err)
   254  		return 1
   255  	}
   256  
   257  	// If we outputted information, then we need to output a newline
   258  	// so that our success message is nicely spaced out from prior text.
   259  	if header {
   260  		c.Ui.Output("")
   261  	}
   262  
   263  	c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccess)))
   264  	if !c.RunningInAutomation {
   265  		// If we're not running in an automation wrapper, give the user
   266  		// some more detailed next steps that are appropriate for interactive
   267  		// shell usage.
   268  		c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccessCLI)))
   269  	}
   270  
   271  	return 0
   272  }
   273  
   274  // Load the complete module tree, and fetch any missing providers.
   275  // This method outputs its own Ui.
   276  func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade bool) error {
   277  	mod, err := c.Module(path)
   278  	if err != nil {
   279  		c.Ui.Error(fmt.Sprintf("Error getting plugins: %s", err))
   280  		return err
   281  	}
   282  
   283  	if err := mod.Validate(); err != nil {
   284  		c.Ui.Error(fmt.Sprintf("Error getting plugins: %s", err))
   285  		return err
   286  	}
   287  
   288  	if err := terraform.CheckRequiredVersion(mod); err != nil {
   289  		c.Ui.Error(err.Error())
   290  		return err
   291  	}
   292  
   293  	var available discovery.PluginMetaSet
   294  	if upgrade {
   295  		// If we're in upgrade mode, we ignore any auto-installed plugins
   296  		// in "available", causing us to reinstall and possibly upgrade them.
   297  		available = c.providerPluginManuallyInstalledSet()
   298  	} else {
   299  		available = c.providerPluginSet()
   300  	}
   301  
   302  	requirements := terraform.ModuleTreeDependencies(mod, state).AllPluginRequirements()
   303  	if len(requirements) == 0 {
   304  		// nothing to initialize
   305  		return nil
   306  	}
   307  
   308  	c.Ui.Output(c.Colorize().Color(
   309  		"\n[reset][bold]Initializing provider plugins...",
   310  	))
   311  
   312  	missing := c.missingPlugins(available, requirements)
   313  	internal := c.internalProviders()
   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  			if _, isInternal := internal[provider]; isInternal {
   324  				// Ignore internal providers; they are not eligible for
   325  				// installation.
   326  				continue
   327  			}
   328  
   329  			_, err := c.providerInstaller.Get(provider, reqd.Versions)
   330  
   331  			if err != nil {
   332  				switch err {
   333  				case discovery.ErrorNoSuchProvider:
   334  					c.Ui.Error(fmt.Sprintf(errProviderNotFound, provider, DefaultPluginVendorDir))
   335  				case discovery.ErrorNoSuitableVersion:
   336  					if reqd.Versions.Unconstrained() {
   337  						// This should never happen, but might crop up if we catch
   338  						// the releases server in a weird state where the provider's
   339  						// directory is present but does not yet contain any
   340  						// versions. We'll treat it like ErrorNoSuchProvider, then.
   341  						c.Ui.Error(fmt.Sprintf(errProviderNotFound, provider, DefaultPluginVendorDir))
   342  					} else {
   343  						c.Ui.Error(fmt.Sprintf(errProviderVersionsUnsuitable, provider, reqd.Versions))
   344  					}
   345  				case discovery.ErrorNoVersionCompatible:
   346  					// FIXME: This error message is sub-awesome because we don't
   347  					// have enough information here to tell the user which versions
   348  					// we considered and which versions might be compatible.
   349  					constraint := reqd.Versions.String()
   350  					if constraint == "" {
   351  						constraint = "(any version)"
   352  					}
   353  					c.Ui.Error(fmt.Sprintf(errProviderIncompatible, provider, constraint))
   354  				default:
   355  					c.Ui.Error(fmt.Sprintf(errProviderInstallError, provider, err.Error(), DefaultPluginVendorDir))
   356  				}
   357  
   358  				errs = multierror.Append(errs, err)
   359  			}
   360  		}
   361  
   362  		if errs != nil {
   363  			return errs
   364  		}
   365  	} else if len(missing) > 0 {
   366  		// we have missing providers, but aren't going to try and download them
   367  		var lines []string
   368  		for provider, reqd := range missing {
   369  			if reqd.Versions.Unconstrained() {
   370  				lines = append(lines, fmt.Sprintf("* %s (any version)\n", provider))
   371  			} else {
   372  				lines = append(lines, fmt.Sprintf("* %s (%s)\n", provider, reqd.Versions))
   373  			}
   374  			errs = multierror.Append(errs, fmt.Errorf("missing provider %q", provider))
   375  		}
   376  		sort.Strings(lines)
   377  		c.Ui.Error(fmt.Sprintf(errMissingProvidersNoInstall, strings.Join(lines, ""), DefaultPluginVendorDir))
   378  		return errs
   379  	}
   380  
   381  	// With all the providers downloaded, we'll generate our lock file
   382  	// that ensures the provider binaries remain unchanged until we init
   383  	// again. If anything changes, other commands that use providers will
   384  	// fail with an error instructing the user to re-run this command.
   385  	available = c.providerPluginSet() // re-discover to see newly-installed plugins
   386  	chosen := choosePlugins(available, internal, requirements)
   387  	digests := map[string][]byte{}
   388  	for name, meta := range chosen {
   389  		digest, err := meta.SHA256()
   390  		if err != nil {
   391  			c.Ui.Error(fmt.Sprintf("failed to read provider plugin %s: %s", meta.Path, err))
   392  			return err
   393  		}
   394  		digests[name] = digest
   395  		if c.ignorePluginChecksum {
   396  			digests[name] = nil
   397  		}
   398  	}
   399  	err = c.providerPluginsLock().Write(digests)
   400  	if err != nil {
   401  		c.Ui.Error(fmt.Sprintf("failed to save provider manifest: %s", err))
   402  		return err
   403  	}
   404  
   405  	{
   406  		// Purge any auto-installed plugins that aren't being used.
   407  		purged, err := c.providerInstaller.PurgeUnused(chosen)
   408  		if err != nil {
   409  			// Failure to purge old plugins is not a fatal error
   410  			c.Ui.Warn(fmt.Sprintf("failed to purge unused plugins: %s", err))
   411  		}
   412  		if purged != nil {
   413  			for meta := range purged {
   414  				log.Printf("[DEBUG] Purged unused %s plugin %s", meta.Name, meta.Path)
   415  			}
   416  		}
   417  	}
   418  
   419  	// If any providers have "floating" versions (completely unconstrained)
   420  	// we'll suggest the user constrain with a pessimistic constraint to
   421  	// avoid implicitly adopting a later major release.
   422  	constraintSuggestions := make(map[string]discovery.ConstraintStr)
   423  	for name, meta := range chosen {
   424  		req := requirements[name]
   425  		if req == nil {
   426  			// should never happen, but we don't want to crash here, so we'll
   427  			// be cautious.
   428  			continue
   429  		}
   430  
   431  		if req.Versions.Unconstrained() && meta.Version != discovery.VersionZero {
   432  			// meta.Version.MustParse is safe here because our "chosen" metas
   433  			// were already filtered for validity of versions.
   434  			constraintSuggestions[name] = meta.Version.MustParse().MinorUpgradeConstraintStr()
   435  		}
   436  	}
   437  	if len(constraintSuggestions) != 0 {
   438  		names := make([]string, 0, len(constraintSuggestions))
   439  		for name := range constraintSuggestions {
   440  			names = append(names, name)
   441  		}
   442  		sort.Strings(names)
   443  
   444  		c.Ui.Output(outputInitProvidersUnconstrained)
   445  		for _, name := range names {
   446  			c.Ui.Output(fmt.Sprintf("* provider.%s: version = %q", name, constraintSuggestions[name]))
   447  		}
   448  	}
   449  
   450  	return nil
   451  }
   452  
   453  func (c *InitCommand) AutocompleteArgs() complete.Predictor {
   454  	return complete.PredictDirs("")
   455  }
   456  
   457  func (c *InitCommand) AutocompleteFlags() complete.Flags {
   458  	return complete.Flags{
   459  		"-backend":        completePredictBoolean,
   460  		"-backend-config": complete.PredictFiles("*.tfvars"), // can also be key=value, but we can't "predict" that
   461  		"-force-copy":     complete.PredictNothing,
   462  		"-from-module":    completePredictModuleSource,
   463  		"-get":            completePredictBoolean,
   464  		"-get-plugins":    completePredictBoolean,
   465  		"-input":          completePredictBoolean,
   466  		"-lock":           completePredictBoolean,
   467  		"-lock-timeout":   complete.PredictAnything,
   468  		"-no-color":       complete.PredictNothing,
   469  		"-plugin-dir":     complete.PredictDirs(""),
   470  		"-reconfigure":    complete.PredictNothing,
   471  		"-upgrade":        completePredictBoolean,
   472  		"-verify-plugins": completePredictBoolean,
   473  	}
   474  }
   475  
   476  func (c *InitCommand) Help() string {
   477  	helpText := `
   478  Usage: terraform init [options] [DIR]
   479  
   480    Initialize a new or existing Terraform working directory by creating
   481    initial files, loading any remote state, downloading modules, etc.
   482  
   483    This is the first command that should be run for any new or existing
   484    Terraform configuration per machine. This sets up all the local data
   485    necessary to run Terraform that is typically not committed to version
   486    control.
   487  
   488    This command is always safe to run multiple times. Though subsequent runs
   489    may give errors, this command will never delete your configuration or
   490    state. Even so, if you have important information, please back it up prior
   491    to running this command, just in case.
   492  
   493    If no arguments are given, the configuration in this working directory
   494    is initialized.
   495  
   496  Options:
   497  
   498    -backend=true        Configure the backend for this configuration.
   499  
   500    -backend-config=path This can be either a path to an HCL file with key/value
   501                         assignments (same format as terraform.tfvars) or a
   502                         'key=value' format. This is merged with what is in the
   503                         configuration file. This can be specified multiple
   504                         times. The backend type must be in the configuration
   505                         itself.
   506  
   507    -force-copy          Suppress prompts about copying state data. This is
   508                         equivalent to providing a "yes" to all confirmation
   509                         prompts.
   510  
   511    -from-module=SOURCE  Copy the contents of the given module into the target
   512                         directory before initialization.
   513  
   514    -get=true            Download any modules for this configuration.
   515  
   516    -get-plugins=true    Download any missing plugins for this configuration.
   517  
   518    -input=true          Ask for input if necessary. If false, will error if
   519                         input was required.
   520  
   521    -lock=true           Lock the state file when locking is supported.
   522  
   523    -lock-timeout=0s     Duration to retry a state lock.
   524  
   525    -no-color            If specified, output won't contain any color.
   526  
   527    -plugin-dir          Directory containing plugin binaries. This overrides all
   528                         default search paths for plugins, and prevents the 
   529                         automatic installation of plugins. This flag can be used
   530                         multiple times.
   531  
   532    -reconfigure         Reconfigure the backend, ignoring any saved
   533                         configuration.
   534  
   535    -upgrade=false       If installing modules (-get) or plugins (-get-plugins),
   536                         ignore previously-downloaded objects and install the
   537                         latest version allowed within configured constraints.
   538  
   539    -verify-plugins=true Verify the authenticity and integrity of automatically
   540                         downloaded plugins.
   541  `
   542  	return strings.TrimSpace(helpText)
   543  }
   544  
   545  func (c *InitCommand) Synopsis() string {
   546  	return "Initialize a Terraform working directory"
   547  }
   548  
   549  const errInitConfigError = `
   550  There are some problems with the configuration, described below.
   551  
   552  The Terraform configuration must be valid before initialization so that
   553  Terraform can determine which modules and providers need to be installed.
   554  `
   555  
   556  const errInitCopyNotEmpty = `
   557  The working directory already contains files. The -from-module option requires
   558  an empty directory into which a copy of the referenced module will be placed.
   559  
   560  To initialize the configuration already in this working directory, omit the
   561  -from-module option.
   562  `
   563  
   564  const outputInitEmpty = `
   565  [reset][bold]Terraform initialized in an empty directory![reset]
   566  
   567  The directory has no Terraform configuration files. You may begin working
   568  with Terraform immediately by creating Terraform configuration files.
   569  `
   570  
   571  const outputInitSuccess = `
   572  [reset][bold][green]Terraform has been successfully initialized![reset][green]
   573  `
   574  
   575  const outputInitSuccessCLI = `[reset][green]
   576  You may now begin working with Terraform. Try running "terraform plan" to see
   577  any changes that are required for your infrastructure. All Terraform commands
   578  should now work.
   579  
   580  If you ever set or change modules or backend configuration for Terraform,
   581  rerun this command to reinitialize your working directory. If you forget, other
   582  commands will detect it and remind you to do so if necessary.
   583  `
   584  
   585  const outputInitProvidersUnconstrained = `
   586  The following providers do not have any version constraints in configuration,
   587  so the latest version was installed.
   588  
   589  To prevent automatic upgrades to new major versions that may contain breaking
   590  changes, it is recommended to add version = "..." constraints to the
   591  corresponding provider blocks in configuration, with the constraint strings
   592  suggested below.
   593  `
   594  
   595  const errProviderNotFound = `
   596  [reset][bold][red]Provider %[1]q not available for installation.[reset][red]
   597  
   598  A provider named %[1]q could not be found in the official repository.
   599  
   600  This may result from mistyping the provider name, or the given provider may
   601  be a third-party provider that cannot be installed automatically.
   602  
   603  In the latter case, the plugin must be installed manually by locating and
   604  downloading a suitable distribution package and placing the plugin's executable
   605  file in the following directory:
   606      %[2]s
   607  
   608  Terraform detects necessary plugins by inspecting the configuration and state.
   609  To view the provider versions requested by each module, run
   610  "terraform providers".
   611  `
   612  
   613  const errProviderVersionsUnsuitable = `
   614  [reset][bold][red]No provider %[1]q plugins meet the constraint %[2]q.[reset][red]
   615  
   616  The version constraint is derived from the "version" argument within the
   617  provider %[1]q block in configuration. Child modules may also apply
   618  provider version constraints. To view the provider versions requested by each
   619  module in the current configuration, run "terraform providers".
   620  
   621  To proceed, the version constraints for this provider must be relaxed by
   622  either adjusting or removing the "version" argument in the provider blocks
   623  throughout the configuration.
   624  `
   625  
   626  const errProviderIncompatible = `
   627  [reset][bold][red]No available provider %[1]q plugins are compatible with this Terraform version.[reset][red]
   628  
   629  From time to time, new Terraform major releases can change the requirements for
   630  plugins such that older plugins become incompatible.
   631  
   632  Terraform checked all of the plugin versions matching the given constraint:
   633      %[2]s
   634  
   635  Unfortunately, none of the suitable versions are compatible with this version
   636  of Terraform. If you have recently upgraded Terraform, it may be necessary to
   637  move to a newer major release of this provider. Alternatively, if you are
   638  attempting to upgrade the provider to a new major version you may need to
   639  also upgrade Terraform to support the new version.
   640  
   641  Consult the documentation for this provider for more information on
   642  compatibility between provider versions and Terraform versions.
   643  `
   644  
   645  const errProviderInstallError = `
   646  [reset][bold][red]Error installing provider %[1]q: %[2]s.[reset][red]
   647  
   648  Terraform analyses the configuration and state and automatically downloads
   649  plugins for the providers used. However, when attempting to download this
   650  plugin an unexpected error occured.
   651  
   652  This may be caused if for some reason Terraform is unable to reach the
   653  plugin repository. The repository may be unreachable if access is blocked
   654  by a firewall.
   655  
   656  If automatic installation is not possible or desirable in your environment,
   657  you may alternatively manually install plugins by downloading a suitable
   658  distribution package and placing the plugin's executable file in the
   659  following directory:
   660      %[3]s
   661  `
   662  
   663  const errMissingProvidersNoInstall = `
   664  [reset][bold][red]Missing required providers.[reset][red]
   665  
   666  The following provider constraints are not met by the currently-installed
   667  provider plugins:
   668  
   669  %[1]s
   670  Terraform can automatically download and install plugins to meet the given
   671  constraints, but this step was skipped due to the use of -get-plugins=false
   672  and/or -plugin-dir on the command line.
   673  
   674  If automatic installation is not possible or desirable in your environment,
   675  you may manually install plugins by downloading a suitable distribution package
   676  and placing the plugin's executable file in one of the directories given in
   677  by -plugin-dir on the command line, or in the following directory if custom
   678  plugin directories are not set:
   679      %[2]s
   680  `