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 `