github.com/jzbruno/terraform@v0.10.3-0.20180104230435-18975d727047/command/meta_backend.go (about) 1 package command 2 3 // This file contains all the Backend-related function calls on Meta, 4 // exported and private. 5 6 import ( 7 "context" 8 "errors" 9 "fmt" 10 "io/ioutil" 11 "log" 12 "path/filepath" 13 "strings" 14 15 "github.com/hashicorp/go-multierror" 16 "github.com/hashicorp/hcl" 17 "github.com/hashicorp/terraform/backend" 18 "github.com/hashicorp/terraform/command/clistate" 19 "github.com/hashicorp/terraform/config" 20 "github.com/hashicorp/terraform/state" 21 "github.com/hashicorp/terraform/terraform" 22 "github.com/mitchellh/mapstructure" 23 24 backendinit "github.com/hashicorp/terraform/backend/init" 25 backendlocal "github.com/hashicorp/terraform/backend/local" 26 ) 27 28 // BackendOpts are the options used to initialize a backend.Backend. 29 type BackendOpts struct { 30 // Module is the root module from which we will extract the terraform and 31 // backend configuration. 32 Config *config.Config 33 34 // ConfigFile is a path to a file that contains configuration that 35 // is merged directly into the backend configuration when loaded 36 // from a file. 37 ConfigFile string 38 39 // ConfigExtra is extra configuration to merge into the backend 40 // configuration after the extra file above. 41 ConfigExtra map[string]interface{} 42 43 // Plan is a plan that is being used. If this is set, the backend 44 // configuration and output configuration will come from this plan. 45 Plan *terraform.Plan 46 47 // Init should be set to true if initialization is allowed. If this is 48 // false, then any configuration that requires configuration will show 49 // an error asking the user to reinitialize. 50 Init bool 51 52 // ForceLocal will force a purely local backend, including state. 53 // You probably don't want to set this. 54 ForceLocal bool 55 } 56 57 // Backend initializes and returns the backend for this CLI session. 58 // 59 // The backend is used to perform the actual Terraform operations. This 60 // abstraction enables easily sliding in new Terraform behavior such as 61 // remote state storage, remote operations, etc. while allowing the CLI 62 // to remain mostly identical. 63 // 64 // This will initialize a new backend for each call, which can carry some 65 // overhead with it. Please reuse the returned value for optimal behavior. 66 // 67 // Only one backend should be used per Meta. This function is stateful 68 // and is unsafe to create multiple backends used at once. This function 69 // can be called multiple times with each backend being "live" (usable) 70 // one at a time. 71 func (m *Meta) Backend(opts *BackendOpts) (backend.Enhanced, error) { 72 // If no opts are set, then initialize 73 if opts == nil { 74 opts = &BackendOpts{} 75 } 76 77 // Initialize a backend from the config unless we're forcing a purely 78 // local operation. 79 var b backend.Backend 80 if !opts.ForceLocal { 81 var err error 82 83 // If we have a plan then, we get the the backend from there. Otherwise, 84 // the backend comes from the configuration. 85 if opts.Plan != nil { 86 b, err = m.backendFromPlan(opts) 87 } else { 88 b, err = m.backendFromConfig(opts) 89 } 90 if err != nil { 91 return nil, err 92 } 93 94 log.Printf("[INFO] command: backend initialized: %T", b) 95 } 96 97 // Setup the CLI opts we pass into backends that support it 98 cliOpts := &backend.CLIOpts{ 99 CLI: m.Ui, 100 CLIColor: m.Colorize(), 101 StatePath: m.statePath, 102 StateOutPath: m.stateOutPath, 103 StateBackupPath: m.backupPath, 104 ContextOpts: m.contextOpts(), 105 Input: m.Input(), 106 RunningInAutomation: m.RunningInAutomation, 107 } 108 109 // Don't validate if we have a plan. Validation is normally harmless here, 110 // but validation requires interpolation, and `file()` function calls may 111 // not have the original files in the current execution context. 112 cliOpts.Validation = opts.Plan == nil 113 114 // If the backend supports CLI initialization, do it. 115 if cli, ok := b.(backend.CLI); ok { 116 if err := cli.CLIInit(cliOpts); err != nil { 117 return nil, fmt.Errorf( 118 "Error initializing backend %T: %s\n\n"+ 119 "This is a bug, please report it to the backend developer", 120 b, err) 121 } 122 } 123 124 // If the result of loading the backend is an enhanced backend, 125 // then return that as-is. This works even if b == nil (it will be !ok). 126 if enhanced, ok := b.(backend.Enhanced); ok { 127 return enhanced, nil 128 } 129 130 // We either have a non-enhanced backend or no backend configured at 131 // all. In either case, we use local as our enhanced backend and the 132 // non-enhanced (if any) as the state backend. 133 134 if !opts.ForceLocal { 135 log.Printf("[INFO] command: backend %T is not enhanced, wrapping in local", b) 136 } 137 138 // Build the local backend 139 local := &backendlocal.Local{Backend: b} 140 if err := local.CLIInit(cliOpts); err != nil { 141 // Local backend isn't allowed to fail. It would be a bug. 142 panic(err) 143 } 144 145 return local, nil 146 } 147 148 // IsLocalBackend returns true if the backend is a local backend. We use this 149 // for some checks that require a remote backend. 150 func (m *Meta) IsLocalBackend(b backend.Backend) bool { 151 // Is it a local backend? 152 bLocal, ok := b.(*backendlocal.Local) 153 154 // If it is, does it not have an alternate state backend? 155 if ok { 156 ok = bLocal.Backend == nil 157 } 158 159 return ok 160 } 161 162 // Operation initializes a new backend.Operation struct. 163 // 164 // This prepares the operation. After calling this, the caller is expected 165 // to modify fields of the operation such as Sequence to specify what will 166 // be called. 167 func (m *Meta) Operation() *backend.Operation { 168 return &backend.Operation{ 169 PlanOutBackend: m.backendState, 170 Targets: m.targets, 171 UIIn: m.UIInput(), 172 UIOut: m.Ui, 173 Workspace: m.Workspace(), 174 LockState: m.stateLock, 175 StateLockTimeout: m.stateLockTimeout, 176 } 177 } 178 179 // backendConfig returns the local configuration for the backend 180 func (m *Meta) backendConfig(opts *BackendOpts) (*config.Backend, error) { 181 if opts.Config == nil { 182 // check if the config was missing, or just not required 183 conf, err := m.Config(".") 184 if err != nil { 185 return nil, err 186 } 187 188 if conf == nil { 189 log.Println("[INFO] command: no config, returning nil") 190 return nil, nil 191 } 192 193 log.Println("[WARNING] BackendOpts.Config not set, but config found") 194 opts.Config = conf 195 } 196 197 c := opts.Config 198 199 // If there is no Terraform configuration block, no backend config 200 if c.Terraform == nil { 201 log.Println("[INFO] command: empty terraform config, returning nil") 202 return nil, nil 203 } 204 205 // Get the configuration for the backend itself. 206 backend := c.Terraform.Backend 207 if backend == nil { 208 log.Println("[INFO] command: empty backend config, returning nil") 209 return nil, nil 210 } 211 212 // If we have a config file set, load that and merge. 213 if opts.ConfigFile != "" { 214 log.Printf( 215 "[DEBUG] command: loading extra backend config from: %s", 216 opts.ConfigFile) 217 rc, err := m.backendConfigFile(opts.ConfigFile) 218 if err != nil { 219 return nil, fmt.Errorf( 220 "Error loading extra configuration file for backend: %s", err) 221 } 222 223 // Merge in the configuration 224 backend.RawConfig = backend.RawConfig.Merge(rc) 225 } 226 227 // If we have extra config values, merge that 228 if len(opts.ConfigExtra) > 0 { 229 log.Printf( 230 "[DEBUG] command: adding extra backend config from CLI") 231 rc, err := config.NewRawConfig(opts.ConfigExtra) 232 if err != nil { 233 return nil, fmt.Errorf( 234 "Error adding extra configuration file for backend: %s", err) 235 } 236 237 // Merge in the configuration 238 backend.RawConfig = backend.RawConfig.Merge(rc) 239 } 240 241 // Validate the backend early. We have to do this before the normal 242 // config validation pass since backend loading happens earlier. 243 if errs := backend.Validate(); len(errs) > 0 { 244 return nil, multierror.Append(nil, errs...) 245 } 246 247 // Return the configuration which may or may not be set 248 return backend, nil 249 } 250 251 // backendConfigFile loads the extra configuration to merge with the 252 // backend configuration from an extra file if specified by 253 // BackendOpts.ConfigFile. 254 func (m *Meta) backendConfigFile(path string) (*config.RawConfig, error) { 255 // Read the file 256 d, err := ioutil.ReadFile(path) 257 if err != nil { 258 return nil, err 259 } 260 261 // Parse it 262 hclRoot, err := hcl.Parse(string(d)) 263 if err != nil { 264 return nil, err 265 } 266 267 // Decode it 268 var c map[string]interface{} 269 if err := hcl.DecodeObject(&c, hclRoot); err != nil { 270 return nil, err 271 } 272 273 return config.NewRawConfig(c) 274 } 275 276 // backendFromConfig returns the initialized (not configured) backend 277 // directly from the config/state.. 278 // 279 // This function handles any edge cases around backend config loading. For 280 // example: legacy remote state, new config changes, backend type changes, 281 // etc. 282 // 283 // This function may query the user for input unless input is disabled, in 284 // which case this function will error. 285 func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, error) { 286 // Get the local backend configuration. 287 c, err := m.backendConfig(opts) 288 if err != nil { 289 return nil, fmt.Errorf("Error loading backend config: %s", err) 290 } 291 292 // cHash defaults to zero unless c is set 293 var cHash uint64 294 if c != nil { 295 // We need to rehash to get the value since we may have merged the 296 // config with an extra ConfigFile. We don't do this when merging 297 // because we do want the ORIGINAL value on c so that we store 298 // that to not detect drift. This is covered in tests. 299 cHash = c.Rehash() 300 } 301 302 // Get the path to where we store a local cache of backend configuration 303 // if we're using a remote backend. This may not yet exist which means 304 // we haven't used a non-local backend before. That is okay. 305 statePath := filepath.Join(m.DataDir(), DefaultStateFilename) 306 sMgr := &state.LocalState{Path: statePath} 307 if err := sMgr.RefreshState(); err != nil { 308 return nil, fmt.Errorf("Error loading state: %s", err) 309 } 310 311 // Load the state, it must be non-nil for the tests below but can be empty 312 s := sMgr.State() 313 if s == nil { 314 log.Printf("[DEBUG] command: no data state file found for backend config") 315 s = terraform.NewState() 316 } 317 318 // if we want to force reconfiguration of the backend, we set the backend 319 // state to nil on this copy. This will direct us through the correct 320 // configuration path in the switch statement below. 321 if m.reconfigure { 322 s.Backend = nil 323 } 324 325 // Upon return, we want to set the state we're using in-memory so that 326 // we can access it for commands. 327 m.backendState = nil 328 defer func() { 329 if s := sMgr.State(); s != nil && !s.Backend.Empty() { 330 m.backendState = s.Backend 331 } 332 }() 333 334 // This giant switch statement covers all eight possible combinations 335 // of state settings between: configuring new backends, saved (previously- 336 // configured) backends, and legacy remote state. 337 switch { 338 // No configuration set at all. Pure local state. 339 case c == nil && s.Remote.Empty() && s.Backend.Empty(): 340 return nil, nil 341 342 // We're unsetting a backend (moving from backend => local) 343 case c == nil && s.Remote.Empty() && !s.Backend.Empty(): 344 if !opts.Init { 345 initReason := fmt.Sprintf( 346 "Unsetting the previously set backend %q", 347 s.Backend.Type) 348 m.backendInitRequired(initReason) 349 return nil, errBackendInitRequired 350 } 351 352 return m.backend_c_r_S(c, sMgr, true) 353 354 // We have a legacy remote state configuration but no new backend config 355 case c == nil && !s.Remote.Empty() && s.Backend.Empty(): 356 return m.backend_c_R_s(c, sMgr) 357 358 // We have a legacy remote state configuration simultaneously with a 359 // saved backend configuration while at the same time disabling backend 360 // configuration. 361 // 362 // This is a naturally impossible case: Terraform will never put you 363 // in this state, though it is theoretically possible through manual edits 364 case c == nil && !s.Remote.Empty() && !s.Backend.Empty(): 365 if !opts.Init { 366 initReason := fmt.Sprintf( 367 "Unsetting the previously set backend %q", 368 s.Backend.Type) 369 m.backendInitRequired(initReason) 370 return nil, errBackendInitRequired 371 } 372 373 return m.backend_c_R_S(c, sMgr) 374 375 // Configuring a backend for the first time. 376 case c != nil && s.Remote.Empty() && s.Backend.Empty(): 377 if !opts.Init { 378 initReason := fmt.Sprintf( 379 "Initial configuration of the requested backend %q", 380 c.Type) 381 m.backendInitRequired(initReason) 382 return nil, errBackendInitRequired 383 } 384 385 return m.backend_C_r_s(c, sMgr) 386 387 // Potentially changing a backend configuration 388 case c != nil && s.Remote.Empty() && !s.Backend.Empty(): 389 // If our configuration is the same, then we're just initializing 390 // a previously configured remote backend. 391 if !s.Backend.Empty() { 392 hash := s.Backend.Hash 393 // on init we need an updated hash containing any extra options 394 // that were added after merging. 395 if opts.Init { 396 hash = s.Backend.Rehash() 397 } 398 if hash == cHash { 399 return m.backend_C_r_S_unchanged(c, sMgr) 400 } 401 } 402 403 if !opts.Init { 404 initReason := fmt.Sprintf( 405 "Backend configuration changed for %q", 406 c.Type) 407 m.backendInitRequired(initReason) 408 return nil, errBackendInitRequired 409 } 410 411 log.Printf( 412 "[WARN] command: backend config change! saved: %d, new: %d", 413 s.Backend.Hash, cHash) 414 return m.backend_C_r_S_changed(c, sMgr, true) 415 416 // Configuring a backend for the first time while having legacy 417 // remote state. This is very possible if a Terraform user configures 418 // a backend prior to ever running Terraform on an old state. 419 case c != nil && !s.Remote.Empty() && s.Backend.Empty(): 420 if !opts.Init { 421 initReason := fmt.Sprintf( 422 "Initial configuration for backend %q", 423 c.Type) 424 m.backendInitRequired(initReason) 425 return nil, errBackendInitRequired 426 } 427 428 return m.backend_C_R_s(c, sMgr) 429 430 // Configuring a backend with both a legacy remote state set 431 // and a pre-existing backend saved. 432 case c != nil && !s.Remote.Empty() && !s.Backend.Empty(): 433 // If the hashes are the same, we have a legacy remote state with 434 // an unchanged stored backend state. 435 hash := s.Backend.Hash 436 if opts.Init { 437 hash = s.Backend.Rehash() 438 } 439 if hash == cHash { 440 if !opts.Init { 441 initReason := fmt.Sprintf( 442 "Legacy remote state found with configured backend %q", 443 c.Type) 444 m.backendInitRequired(initReason) 445 return nil, errBackendInitRequired 446 } 447 448 return m.backend_C_R_S_unchanged(c, sMgr, true) 449 } 450 451 if !opts.Init { 452 initReason := fmt.Sprintf( 453 "Reconfiguring the backend %q", 454 c.Type) 455 m.backendInitRequired(initReason) 456 return nil, errBackendInitRequired 457 } 458 459 // We have change in all three 460 return m.backend_C_R_S_changed(c, sMgr) 461 default: 462 // This should be impossible since all state possibilties are 463 // tested above, but we need a default case anyways and we should 464 // protect against the scenario where a case is somehow removed. 465 return nil, fmt.Errorf( 466 "Unhandled backend configuration state. This is a bug. Please\n"+ 467 "report this error with the following information.\n\n"+ 468 "Config Nil: %v\n"+ 469 "Saved Backend Empty: %v\n"+ 470 "Legacy Remote Empty: %v\n", 471 c == nil, s.Backend.Empty(), s.Remote.Empty()) 472 } 473 } 474 475 // backendFromPlan loads the backend from a given plan file. 476 func (m *Meta) backendFromPlan(opts *BackendOpts) (backend.Backend, error) { 477 // Precondition check 478 if opts.Plan == nil { 479 panic("plan should not be nil") 480 } 481 482 // We currently don't allow "-state" to be specified. 483 if m.statePath != "" { 484 return nil, fmt.Errorf( 485 "State path cannot be specified with a plan file. The plan itself contains\n" + 486 "the state to use. If you wish to change that, please create a new plan\n" + 487 "and specify the state path when creating the plan.") 488 } 489 490 planBackend := opts.Plan.Backend 491 planState := opts.Plan.State 492 if planState == nil { 493 // The state can be nil, we just have to make it empty for the logic 494 // in this function. 495 planState = terraform.NewState() 496 } 497 498 // Validation only for non-local plans 499 local := planState.Remote.Empty() && planBackend.Empty() 500 if !local { 501 // We currently don't allow "-state-out" to be specified. 502 if m.stateOutPath != "" { 503 return nil, fmt.Errorf(strings.TrimSpace(errBackendPlanStateFlag)) 504 } 505 } 506 507 /* 508 // Determine the path where we'd be writing state 509 path := DefaultStateFilename 510 if !planState.Remote.Empty() || !planBackend.Empty() { 511 path = filepath.Join(m.DataDir(), DefaultStateFilename) 512 } 513 514 // If the path exists, then we need to verify we're writing the same 515 // state lineage. If the path doesn't exist that's okay. 516 _, err := os.Stat(path) 517 if err != nil && !os.IsNotExist(err) { 518 return nil, fmt.Errorf("Error checking state destination: %s", err) 519 } 520 if err == nil { 521 // The file exists, we need to read it and compare 522 if err := m.backendFromPlan_compareStates(state, path); err != nil { 523 return nil, err 524 } 525 } 526 */ 527 528 // If we have a stateOutPath, we must also specify it as the 529 // input path so we can check it properly. We restore it after this 530 // function exits. 531 original := m.statePath 532 m.statePath = m.stateOutPath 533 defer func() { m.statePath = original }() 534 535 var b backend.Backend 536 var err error 537 switch { 538 // No remote state at all, all local 539 case planState.Remote.Empty() && planBackend.Empty(): 540 log.Printf("[INFO] command: initializing local backend from plan (not set)") 541 542 // Get the local backend 543 b, err = m.Backend(&BackendOpts{ForceLocal: true}) 544 545 // New backend configuration set 546 case planState.Remote.Empty() && !planBackend.Empty(): 547 log.Printf( 548 "[INFO] command: initializing backend from plan: %s", 549 planBackend.Type) 550 551 b, err = m.backendInitFromSaved(planBackend) 552 553 // Legacy remote state set 554 case !planState.Remote.Empty() && planBackend.Empty(): 555 log.Printf( 556 "[INFO] command: initializing legacy remote backend from plan: %s", 557 planState.Remote.Type) 558 559 // Write our current state to an inmemory state just so that we 560 // have it in the format of state.State 561 inmem := &state.InmemState{} 562 inmem.WriteState(planState) 563 564 // Get the backend through the normal means of legacy state 565 b, err = m.backend_c_R_s(nil, inmem) 566 567 // Both set, this can't happen in a plan. 568 case !planState.Remote.Empty() && !planBackend.Empty(): 569 return nil, fmt.Errorf(strings.TrimSpace(errBackendPlanBoth)) 570 } 571 572 // If we had an error, return that 573 if err != nil { 574 return nil, err 575 } 576 577 env := m.Workspace() 578 579 // Get the state so we can determine the effect of using this plan 580 realMgr, err := b.State(env) 581 if err != nil { 582 return nil, fmt.Errorf("Error reading state: %s", err) 583 } 584 585 if m.stateLock { 586 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 587 defer cancel() 588 589 // Lock the state if we can 590 lockInfo := state.NewLockInfo() 591 lockInfo.Operation = "backend from plan" 592 593 lockID, err := clistate.Lock(lockCtx, realMgr, lockInfo, m.Ui, m.Colorize()) 594 if err != nil { 595 return nil, fmt.Errorf("Error locking state: %s", err) 596 } 597 defer clistate.Unlock(realMgr, lockID, m.Ui, m.Colorize()) 598 } 599 600 if err := realMgr.RefreshState(); err != nil { 601 return nil, fmt.Errorf("Error reading state: %s", err) 602 } 603 real := realMgr.State() 604 if real != nil { 605 // If they're not the same lineage, don't allow this 606 if !real.SameLineage(planState) { 607 return nil, fmt.Errorf(strings.TrimSpace(errBackendPlanLineageDiff)) 608 } 609 610 // Compare ages 611 comp, err := real.CompareAges(planState) 612 if err != nil { 613 return nil, fmt.Errorf("Error comparing state ages for safety: %s", err) 614 } 615 switch comp { 616 case terraform.StateAgeEqual: 617 // State ages are equal, this is perfect 618 619 case terraform.StateAgeReceiverOlder: 620 // Real state is somehow older, this is okay. 621 622 case terraform.StateAgeReceiverNewer: 623 // If we have an older serial it is a problem but if we have a 624 // differing serial but are still identical, just let it through. 625 if real.Equal(planState) { 626 log.Printf( 627 "[WARN] command: state in plan has older serial, but Equal is true") 628 break 629 } 630 631 // The real state is newer, this is not allowed. 632 return nil, fmt.Errorf( 633 strings.TrimSpace(errBackendPlanOlder), 634 planState.Serial, real.Serial) 635 } 636 } 637 638 // Write the state 639 newState := opts.Plan.State.DeepCopy() 640 if newState != nil { 641 newState.Remote = nil 642 newState.Backend = nil 643 } 644 645 // realMgr locked above 646 if err := realMgr.WriteState(newState); err != nil { 647 return nil, fmt.Errorf("Error writing state: %s", err) 648 } 649 if err := realMgr.PersistState(); err != nil { 650 return nil, fmt.Errorf("Error writing state: %s", err) 651 } 652 653 return b, nil 654 } 655 656 //------------------------------------------------------------------- 657 // Backend Config Scenarios 658 // 659 // The functions below cover handling all the various scenarios that 660 // can exist when loading a backend. They are named in the format of 661 // "backend_C_R_S" where C, R, S may be upper or lowercase. Lowercase 662 // means it is false, uppercase means it is true. The full set of eight 663 // possible cases is handled. 664 // 665 // The fields are: 666 // 667 // * C - Backend configuration is set and changed in TF files 668 // * R - Legacy remote state is set 669 // * S - Backend configuration is set in the state 670 // 671 //------------------------------------------------------------------- 672 673 // Unconfiguring a backend (moving from backend => local). 674 func (m *Meta) backend_c_r_S( 675 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 676 s := sMgr.State() 677 678 // Get the backend type for output 679 backendType := s.Backend.Type 680 681 m.Ui.Output(fmt.Sprintf(strings.TrimSpace(outputBackendMigrateLocal), s.Backend.Type)) 682 683 // Grab a purely local backend to get the local state if it exists 684 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 685 if err != nil { 686 return nil, fmt.Errorf(strings.TrimSpace(errBackendLocalRead), err) 687 } 688 689 // Initialize the configured backend 690 b, err := m.backend_C_r_S_unchanged(c, sMgr) 691 if err != nil { 692 return nil, fmt.Errorf( 693 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 694 } 695 696 // Perform the migration 697 err = m.backendMigrateState(&backendMigrateOpts{ 698 OneType: s.Backend.Type, 699 TwoType: "local", 700 One: b, 701 Two: localB, 702 }) 703 if err != nil { 704 return nil, err 705 } 706 707 // Remove the stored metadata 708 s.Backend = nil 709 if err := sMgr.WriteState(s); err != nil { 710 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err) 711 } 712 if err := sMgr.PersistState(); err != nil { 713 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err) 714 } 715 716 if output { 717 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 718 "[reset][green]\n\n"+ 719 strings.TrimSpace(successBackendUnset), backendType))) 720 } 721 722 // Return no backend 723 return nil, nil 724 } 725 726 // Legacy remote state 727 func (m *Meta) backend_c_R_s( 728 c *config.Backend, sMgr state.State) (backend.Backend, error) { 729 s := sMgr.State() 730 731 // Warn the user 732 m.Ui.Warn(strings.TrimSpace(warnBackendLegacy) + "\n") 733 734 // We need to convert the config to map[string]interface{} since that 735 // is what the backends expect. 736 var configMap map[string]interface{} 737 if err := mapstructure.Decode(s.Remote.Config, &configMap); err != nil { 738 return nil, fmt.Errorf("Error configuring remote state: %s", err) 739 } 740 741 // Create the config 742 rawC, err := config.NewRawConfig(configMap) 743 if err != nil { 744 return nil, fmt.Errorf("Error configuring remote state: %s", err) 745 } 746 config := terraform.NewResourceConfig(rawC) 747 748 // Get the backend 749 f := backendinit.Backend(s.Remote.Type) 750 if f == nil { 751 return nil, fmt.Errorf(strings.TrimSpace(errBackendLegacyUnknown), s.Remote.Type) 752 } 753 b := f() 754 755 // Configure 756 if err := b.Configure(config); err != nil { 757 return nil, fmt.Errorf(errBackendLegacyConfig, err) 758 } 759 760 return b, nil 761 } 762 763 // Unsetting backend, saved backend, legacy remote state 764 func (m *Meta) backend_c_R_S( 765 c *config.Backend, sMgr state.State) (backend.Backend, error) { 766 // Notify the user 767 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 768 "[reset]%s\n\n", 769 strings.TrimSpace(outputBackendUnsetWithLegacy)))) 770 771 // Get the backend type for later 772 backendType := sMgr.State().Backend.Type 773 774 // First, perform the configured => local tranasition 775 if _, err := m.backend_c_r_S(c, sMgr, false); err != nil { 776 return nil, err 777 } 778 779 // Grab a purely local backend 780 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 781 if err != nil { 782 return nil, fmt.Errorf(errBackendLocalRead, err) 783 } 784 785 // Grab the state 786 s := sMgr.State() 787 788 m.Ui.Output(strings.TrimSpace(outputBackendMigrateLegacy)) 789 // Initialize the legacy backend 790 oldB, err := m.backendInitFromLegacy(s.Remote) 791 if err != nil { 792 return nil, err 793 } 794 795 // Perform the migration 796 err = m.backendMigrateState(&backendMigrateOpts{ 797 OneType: s.Remote.Type, 798 TwoType: "local", 799 One: oldB, 800 Two: localB, 801 }) 802 if err != nil { 803 return nil, err 804 } 805 806 // Unset the remote state 807 s = sMgr.State() 808 if s == nil { 809 s = terraform.NewState() 810 } 811 s.Remote = nil 812 if err := sMgr.WriteState(s); err != nil { 813 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 814 } 815 if err := sMgr.PersistState(); err != nil { 816 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 817 } 818 819 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 820 "[reset][green]\n\n"+ 821 strings.TrimSpace(successBackendUnset), backendType))) 822 823 return nil, nil 824 } 825 826 // Configuring a backend for the first time with legacy remote state. 827 func (m *Meta) backend_C_R_s( 828 c *config.Backend, sMgr state.State) (backend.Backend, error) { 829 // Notify the user 830 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 831 "[reset]%s\n\n", 832 strings.TrimSpace(outputBackendConfigureWithLegacy)))) 833 834 // First, configure the new backend 835 b, err := m.backendInitFromConfig(c) 836 if err != nil { 837 return nil, err 838 } 839 840 // Next, save the new configuration. This will not overwrite our 841 // legacy remote state. We'll handle that after. 842 s := sMgr.State() 843 if s == nil { 844 s = terraform.NewState() 845 } 846 s.Backend = &terraform.BackendState{ 847 Type: c.Type, 848 Config: c.RawConfig.Raw, 849 Hash: c.Hash, 850 } 851 if err := sMgr.WriteState(s); err != nil { 852 return nil, fmt.Errorf(errBackendWriteSaved, err) 853 } 854 if err := sMgr.PersistState(); err != nil { 855 return nil, fmt.Errorf(errBackendWriteSaved, err) 856 } 857 858 // I don't know how this is possible but if we don't have remote 859 // state config anymore somehow, just return the backend. This 860 // shouldn't be possible, though. 861 if s.Remote.Empty() { 862 return b, nil 863 } 864 865 m.Ui.Output(strings.TrimSpace(outputBackendMigrateLegacy)) 866 // Initialize the legacy backend 867 oldB, err := m.backendInitFromLegacy(s.Remote) 868 if err != nil { 869 return nil, err 870 } 871 872 // Perform the migration 873 err = m.backendMigrateState(&backendMigrateOpts{ 874 OneType: s.Remote.Type, 875 TwoType: c.Type, 876 One: oldB, 877 Two: b, 878 }) 879 if err != nil { 880 return nil, err 881 } 882 883 // Unset the remote state 884 s = sMgr.State() 885 if s == nil { 886 s = terraform.NewState() 887 } 888 s.Remote = nil 889 if err := sMgr.WriteState(s); err != nil { 890 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 891 } 892 if err := sMgr.PersistState(); err != nil { 893 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 894 } 895 896 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 897 "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 898 899 return b, nil 900 } 901 902 // Configuring a backend for the first time. 903 func (m *Meta) backend_C_r_s( 904 c *config.Backend, sMgr state.State) (backend.Backend, error) { 905 // Get the backend 906 b, err := m.backendInitFromConfig(c) 907 if err != nil { 908 return nil, err 909 } 910 911 // Grab a purely local backend to get the local state if it exists 912 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 913 if err != nil { 914 return nil, fmt.Errorf(errBackendLocalRead, err) 915 } 916 917 env := m.Workspace() 918 919 localState, err := localB.State(env) 920 if err != nil { 921 return nil, fmt.Errorf(errBackendLocalRead, err) 922 } 923 if err := localState.RefreshState(); err != nil { 924 return nil, fmt.Errorf(errBackendLocalRead, err) 925 } 926 927 // If the local state is not empty, we need to potentially do a 928 // state migration to the new backend (with user permission), unless the 929 // destination is also "local" 930 if localS := localState.State(); !localS.Empty() { 931 // Perform the migration 932 err = m.backendMigrateState(&backendMigrateOpts{ 933 OneType: "local", 934 TwoType: c.Type, 935 One: localB, 936 Two: b, 937 }) 938 if err != nil { 939 return nil, err 940 } 941 942 // we usually remove the local state after migration to prevent 943 // confusion, but adding a default local backend block to the config 944 // can get us here too. Don't delete our state if the old and new paths 945 // are the same. 946 erase := true 947 if newLocalB, ok := b.(*backendlocal.Local); ok { 948 if localB, ok := localB.(*backendlocal.Local); ok { 949 if newLocalB.StatePath == localB.StatePath { 950 erase = false 951 } 952 } 953 } 954 955 if erase { 956 // We always delete the local state, unless that was our new state too. 957 if err := localState.WriteState(nil); err != nil { 958 return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) 959 } 960 if err := localState.PersistState(); err != nil { 961 return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) 962 } 963 } 964 } 965 966 if m.stateLock { 967 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 968 defer cancel() 969 970 // Lock the state if we can 971 lockInfo := state.NewLockInfo() 972 lockInfo.Operation = "backend from config" 973 974 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 975 if err != nil { 976 return nil, fmt.Errorf("Error locking state: %s", err) 977 } 978 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 979 } 980 981 // Store the metadata in our saved state location 982 s := sMgr.State() 983 if s == nil { 984 s = terraform.NewState() 985 } 986 s.Backend = &terraform.BackendState{ 987 Type: c.Type, 988 Config: c.RawConfig.Raw, 989 Hash: c.Hash, 990 } 991 992 if err := sMgr.WriteState(s); err != nil { 993 return nil, fmt.Errorf(errBackendWriteSaved, err) 994 } 995 if err := sMgr.PersistState(); err != nil { 996 return nil, fmt.Errorf(errBackendWriteSaved, err) 997 } 998 999 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1000 "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 1001 1002 // Return the backend 1003 return b, nil 1004 } 1005 1006 // Changing a previously saved backend. 1007 func (m *Meta) backend_C_r_S_changed( 1008 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 1009 if output { 1010 // Notify the user 1011 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1012 "[reset]%s\n\n", 1013 strings.TrimSpace(outputBackendReconfigure)))) 1014 } 1015 1016 // Get the old state 1017 s := sMgr.State() 1018 1019 // Get the backend 1020 b, err := m.backendInitFromConfig(c) 1021 if err != nil { 1022 return nil, fmt.Errorf( 1023 "Error initializing new backend: %s", err) 1024 } 1025 1026 // no need to confuse the user if the backend types are the same 1027 if s.Backend.Type != c.Type { 1028 m.Ui.Output(strings.TrimSpace(fmt.Sprintf(outputBackendMigrateChange, s.Backend.Type, c.Type))) 1029 } 1030 1031 // Grab the existing backend 1032 oldB, err := m.backend_C_r_S_unchanged(c, sMgr) 1033 if err != nil { 1034 return nil, fmt.Errorf( 1035 "Error loading previously configured backend: %s", err) 1036 } 1037 1038 // Perform the migration 1039 err = m.backendMigrateState(&backendMigrateOpts{ 1040 OneType: s.Backend.Type, 1041 TwoType: c.Type, 1042 One: oldB, 1043 Two: b, 1044 }) 1045 if err != nil { 1046 return nil, err 1047 } 1048 1049 if m.stateLock { 1050 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 1051 defer cancel() 1052 1053 // Lock the state if we can 1054 lockInfo := state.NewLockInfo() 1055 lockInfo.Operation = "backend from config" 1056 1057 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 1058 if err != nil { 1059 return nil, fmt.Errorf("Error locking state: %s", err) 1060 } 1061 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 1062 } 1063 1064 // Update the backend state 1065 s = sMgr.State() 1066 if s == nil { 1067 s = terraform.NewState() 1068 } 1069 s.Backend = &terraform.BackendState{ 1070 Type: c.Type, 1071 Config: c.RawConfig.Raw, 1072 Hash: c.Hash, 1073 } 1074 1075 if err := sMgr.WriteState(s); err != nil { 1076 return nil, fmt.Errorf(errBackendWriteSaved, err) 1077 } 1078 if err := sMgr.PersistState(); err != nil { 1079 return nil, fmt.Errorf(errBackendWriteSaved, err) 1080 } 1081 1082 if output { 1083 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1084 "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 1085 } 1086 1087 return b, nil 1088 } 1089 1090 // Initiailizing an unchanged saved backend 1091 func (m *Meta) backend_C_r_S_unchanged( 1092 c *config.Backend, sMgr state.State) (backend.Backend, error) { 1093 s := sMgr.State() 1094 1095 // it's possible for a backend to be unchanged, and the config itself to 1096 // have changed by moving a parameter from the config to `-backend-config` 1097 // In this case we only need to update the Hash. 1098 if c != nil && s.Backend.Hash != c.Hash { 1099 s.Backend.Hash = c.Hash 1100 if err := sMgr.WriteState(s); err != nil { 1101 return nil, fmt.Errorf(errBackendWriteSaved, err) 1102 } 1103 } 1104 1105 // Create the config. We do this from the backend state since this 1106 // has the complete configuration data whereas the config itself 1107 // may require input. 1108 rawC, err := config.NewRawConfig(s.Backend.Config) 1109 if err != nil { 1110 return nil, fmt.Errorf("Error configuring backend: %s", err) 1111 } 1112 config := terraform.NewResourceConfig(rawC) 1113 1114 // Get the backend 1115 f := backendinit.Backend(s.Backend.Type) 1116 if f == nil { 1117 return nil, fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type) 1118 } 1119 b := f() 1120 1121 // Configure 1122 if err := b.Configure(config); err != nil { 1123 return nil, fmt.Errorf(errBackendSavedConfig, s.Backend.Type, err) 1124 } 1125 1126 return b, nil 1127 } 1128 1129 // Initiailizing a changed saved backend with legacy remote state. 1130 func (m *Meta) backend_C_R_S_changed( 1131 c *config.Backend, sMgr state.State) (backend.Backend, error) { 1132 // Notify the user 1133 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1134 "[reset]%s\n\n", 1135 strings.TrimSpace(outputBackendSavedWithLegacyChanged)))) 1136 1137 // Reconfigure the backend first 1138 if _, err := m.backend_C_r_S_changed(c, sMgr, false); err != nil { 1139 return nil, err 1140 } 1141 1142 // Handle the case where we have all set but unchanged 1143 b, err := m.backend_C_R_S_unchanged(c, sMgr, false) 1144 if err != nil { 1145 return nil, err 1146 } 1147 1148 // Output success message 1149 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1150 "[reset][green]\n\n"+ 1151 strings.TrimSpace(successBackendReconfigureWithLegacy), c.Type))) 1152 1153 return b, nil 1154 } 1155 1156 // Initiailizing an unchanged saved backend with legacy remote state. 1157 func (m *Meta) backend_C_R_S_unchanged( 1158 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 1159 if output { 1160 // Notify the user 1161 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1162 "[reset]%s\n\n", 1163 strings.TrimSpace(outputBackendSavedWithLegacy)))) 1164 } 1165 1166 // Load the backend from the state 1167 s := sMgr.State() 1168 b, err := m.backendInitFromSaved(s.Backend) 1169 if err != nil { 1170 return nil, err 1171 } 1172 1173 m.Ui.Output(strings.TrimSpace(outputBackendMigrateLegacy)) 1174 1175 // Initialize the legacy backend 1176 oldB, err := m.backendInitFromLegacy(s.Remote) 1177 if err != nil { 1178 return nil, err 1179 } 1180 1181 // Perform the migration 1182 err = m.backendMigrateState(&backendMigrateOpts{ 1183 OneType: s.Remote.Type, 1184 TwoType: s.Backend.Type, 1185 One: oldB, 1186 Two: b, 1187 }) 1188 if err != nil { 1189 return nil, err 1190 } 1191 1192 if m.stateLock { 1193 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 1194 defer cancel() 1195 1196 // Lock the state if we can 1197 lockInfo := state.NewLockInfo() 1198 lockInfo.Operation = "backend from config" 1199 1200 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 1201 if err != nil { 1202 return nil, fmt.Errorf("Error locking state: %s", err) 1203 } 1204 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 1205 } 1206 1207 // Unset the remote state 1208 s = sMgr.State() 1209 if s == nil { 1210 s = terraform.NewState() 1211 } 1212 s.Remote = nil 1213 1214 if err := sMgr.WriteState(s); err != nil { 1215 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 1216 } 1217 if err := sMgr.PersistState(); err != nil { 1218 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 1219 } 1220 1221 if output { 1222 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1223 "[reset][green]\n\n"+ 1224 strings.TrimSpace(successBackendLegacyUnset), s.Backend.Type))) 1225 } 1226 1227 return b, nil 1228 } 1229 1230 //------------------------------------------------------------------- 1231 // Reusable helper functions for backend management 1232 //------------------------------------------------------------------- 1233 1234 func (m *Meta) backendInitFromConfig(c *config.Backend) (backend.Backend, error) { 1235 // Create the config. 1236 config := terraform.NewResourceConfig(c.RawConfig) 1237 1238 // Get the backend 1239 f := backendinit.Backend(c.Type) 1240 if f == nil { 1241 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewUnknown), c.Type) 1242 } 1243 b := f() 1244 1245 // TODO: test 1246 // Ask for input if we have input enabled 1247 if m.Input() { 1248 var err error 1249 config, err = b.Input(m.UIInput(), config) 1250 if err != nil { 1251 return nil, fmt.Errorf( 1252 "Error asking for input to configure the backend %q: %s", 1253 c.Type, err) 1254 } 1255 } 1256 1257 // Validate 1258 warns, errs := b.Validate(config) 1259 for _, warning := range warns { 1260 // We just write warnings directly to the UI. This isn't great 1261 // since we're a bit deep here to be pushing stuff out into the 1262 // UI, but sufficient to let us print out deprecation warnings 1263 // and the like. 1264 m.Ui.Warn(warning) 1265 } 1266 if len(errs) > 0 { 1267 return nil, fmt.Errorf( 1268 "Error configuring the backend %q: %s", 1269 c.Type, multierror.Append(nil, errs...)) 1270 } 1271 1272 // Configure 1273 if err := b.Configure(config); err != nil { 1274 return nil, fmt.Errorf(errBackendNewConfig, c.Type, err) 1275 } 1276 1277 return b, nil 1278 } 1279 1280 func (m *Meta) backendInitFromLegacy(s *terraform.RemoteState) (backend.Backend, error) { 1281 // We need to convert the config to map[string]interface{} since that 1282 // is what the backends expect. 1283 var configMap map[string]interface{} 1284 if err := mapstructure.Decode(s.Config, &configMap); err != nil { 1285 return nil, fmt.Errorf("Error configuring remote state: %s", err) 1286 } 1287 1288 // Create the config 1289 rawC, err := config.NewRawConfig(configMap) 1290 if err != nil { 1291 return nil, fmt.Errorf("Error configuring remote state: %s", err) 1292 } 1293 config := terraform.NewResourceConfig(rawC) 1294 1295 // Get the backend 1296 f := backendinit.Backend(s.Type) 1297 if f == nil { 1298 return nil, fmt.Errorf(strings.TrimSpace(errBackendLegacyUnknown), s.Type) 1299 } 1300 b := f() 1301 1302 // Configure 1303 if err := b.Configure(config); err != nil { 1304 return nil, fmt.Errorf(errBackendLegacyConfig, err) 1305 } 1306 1307 return b, nil 1308 } 1309 1310 func (m *Meta) backendInitFromSaved(s *terraform.BackendState) (backend.Backend, error) { 1311 // Create the config. We do this from the backend state since this 1312 // has the complete configuration data whereas the config itself 1313 // may require input. 1314 rawC, err := config.NewRawConfig(s.Config) 1315 if err != nil { 1316 return nil, fmt.Errorf("Error configuring backend: %s", err) 1317 } 1318 config := terraform.NewResourceConfig(rawC) 1319 1320 // Get the backend 1321 f := backendinit.Backend(s.Type) 1322 if f == nil { 1323 return nil, fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Type) 1324 } 1325 b := f() 1326 1327 // Configure 1328 if err := b.Configure(config); err != nil { 1329 return nil, fmt.Errorf(errBackendSavedConfig, s.Type, err) 1330 } 1331 1332 return b, nil 1333 } 1334 1335 func (m *Meta) backendInitRequired(reason string) { 1336 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1337 "[reset]"+strings.TrimSpace(errBackendInit)+"\n", reason))) 1338 } 1339 1340 //------------------------------------------------------------------- 1341 // Output constants and initialization code 1342 //------------------------------------------------------------------- 1343 1344 // errBackendInitRequired is the final error message shown when reinit 1345 // is required for some reason. The error message includes the reason. 1346 var errBackendInitRequired = errors.New( 1347 "Initialization required. Please see the error message above.") 1348 1349 const errBackendLegacyConfig = ` 1350 One or more errors occurred while configuring the legacy remote state. 1351 If fixing these errors requires changing your remote state configuration, 1352 you must switch your configuration to the new remote backend configuration. 1353 You can learn more about remote backends at the URL below: 1354 1355 https://www.terraform.io/docs/backends/index.html 1356 1357 The error(s) configuring the legacy remote state: 1358 1359 %s 1360 ` 1361 1362 const errBackendLegacyUnknown = ` 1363 The legacy remote state type %q could not be found. 1364 1365 Terraform 0.9.0 shipped with backwards compatibility for all built-in 1366 legacy remote state types. This error may mean that you were using a 1367 custom Terraform build that perhaps supported a different type of 1368 remote state. 1369 1370 Please check with the creator of the remote state above and try again. 1371 ` 1372 1373 const errBackendLocalRead = ` 1374 Error reading local state: %s 1375 1376 Terraform is trying to read your local state to determine if there is 1377 state to migrate to your newly configured backend. Terraform can't continue 1378 without this check because that would risk losing state. Please resolve the 1379 error above and try again. 1380 ` 1381 1382 const errBackendMigrateLocalDelete = ` 1383 Error deleting local state after migration: %s 1384 1385 Your local state is deleted after successfully migrating it to the newly 1386 configured backend. As part of the deletion process, a backup is made at 1387 the standard backup path unless explicitly asked not to. To cleanly operate 1388 with a backend, we must delete the local state file. Please resolve the 1389 issue above and retry the command. 1390 ` 1391 1392 const errBackendMigrateNew = ` 1393 Error migrating local state to backend: %s 1394 1395 Your local state remains intact and unmodified. Please resolve the error 1396 above and try again. 1397 ` 1398 1399 const errBackendNewConfig = ` 1400 Error configuring the backend %q: %s 1401 1402 Please update the configuration in your Terraform files to fix this error 1403 then run this command again. 1404 ` 1405 1406 const errBackendNewRead = ` 1407 Error reading newly configured backend state: %s 1408 1409 Terraform is trying to read the state from your newly configured backend 1410 to determine the copy process for your existing state. Backends are expected 1411 to not error even if there is no state yet written. Please resolve the 1412 error above and try again. 1413 ` 1414 1415 const errBackendNewUnknown = ` 1416 The backend %q could not be found. 1417 1418 This is the backend specified in your Terraform configuration file. 1419 This error could be a simple typo in your configuration, but it can also 1420 be caused by using a Terraform version that doesn't support the specified 1421 backend type. Please check your configuration and your Terraform version. 1422 1423 If you'd like to run Terraform and store state locally, you can fix this 1424 error by removing the backend configuration from your configuration. 1425 ` 1426 1427 const errBackendRemoteRead = ` 1428 Error reading backend state: %s 1429 1430 Terraform is trying to read the state from your configured backend to 1431 determine if there is any migration steps necessary. Terraform can't continue 1432 without this check because that would risk losing state. Please resolve the 1433 error above and try again. 1434 ` 1435 1436 const errBackendSavedConfig = ` 1437 Error configuring the backend %q: %s 1438 1439 Please update the configuration in your Terraform files to fix this error. 1440 If you'd like to update the configuration interactively without storing 1441 the values in your configuration, run "terraform init". 1442 ` 1443 1444 const errBackendSavedUnsetConfig = ` 1445 Error configuring the existing backend %q: %s 1446 1447 Terraform must configure the existing backend in order to copy the state 1448 from the existing backend, as requested. Please resolve the error and try 1449 again. If you choose to not copy the existing state, Terraform will not 1450 configure the backend. If the configuration is invalid, please update your 1451 Terraform configuration with proper configuration for this backend first 1452 before unsetting the backend. 1453 ` 1454 1455 const errBackendSavedUnknown = ` 1456 The backend %q could not be found. 1457 1458 This is the backend that this Terraform environment is configured to use 1459 both in your configuration and saved locally as your last-used backend. 1460 If it isn't found, it could mean an alternate version of Terraform was 1461 used with this configuration. Please use the proper version of Terraform that 1462 contains support for this backend. 1463 1464 If you'd like to force remove this backend, you must update your configuration 1465 to not use the backend and run "terraform init" (or any other command) again. 1466 ` 1467 1468 const errBackendClearLegacy = ` 1469 Error clearing the legacy remote state configuration: %s 1470 1471 Terraform completed configuring your backend. It is now safe to remove 1472 the legacy remote state configuration, but an error occurred while trying 1473 to do so. Please look at the error above, resolve it, and try again. 1474 ` 1475 1476 const errBackendClearSaved = ` 1477 Error clearing the backend configuration: %s 1478 1479 Terraform removes the saved backend configuration when you're removing a 1480 configured backend. This must be done so future Terraform runs know to not 1481 use the backend configuration. Please look at the error above, resolve it, 1482 and try again. 1483 ` 1484 1485 const errBackendInit = ` 1486 [reset][bold][yellow]Backend reinitialization required. Please run "terraform init".[reset] 1487 [yellow]Reason: %s 1488 1489 The "backend" is the interface that Terraform uses to store state, 1490 perform operations, etc. If this message is showing up, it means that the 1491 Terraform configuration you're using is using a custom configuration for 1492 the Terraform backend. 1493 1494 Changes to backend configurations require reinitialization. This allows 1495 Terraform to setup the new configuration, copy existing state, etc. This is 1496 only done during "terraform init". Please run that command now then try again. 1497 1498 If the change reason above is incorrect, please verify your configuration 1499 hasn't changed and try again. At this point, no changes to your existing 1500 configuration or state have been made. 1501 ` 1502 1503 const errBackendWriteSaved = ` 1504 Error saving the backend configuration: %s 1505 1506 Terraform saves the complete backend configuration in a local file for 1507 configuring the backend on future operations. This cannot be disabled. Errors 1508 are usually due to simple file permission errors. Please look at the error 1509 above, resolve it, and try again. 1510 ` 1511 1512 const errBackendPlanBoth = ` 1513 The plan file contained both a legacy remote state and backend configuration. 1514 This is not allowed. Please recreate the plan file with the latest version of 1515 Terraform. 1516 ` 1517 1518 const errBackendPlanLineageDiff = ` 1519 The plan file contains a state with a differing lineage than the current 1520 state. By continuing, your current state would be overwritten by the state 1521 in the plan. Please either update the plan with the latest state or delete 1522 your current state and try again. 1523 1524 "Lineage" is a unique identifier generated only once on the creation of 1525 a new, empty state. If these values differ, it means they were created new 1526 at different times. Therefore, Terraform must assume that they're completely 1527 different states. 1528 1529 The most common cause of seeing this error is using a plan that was 1530 created against a different state. Perhaps the plan is very old and the 1531 state has since been recreated, or perhaps the plan was against a competely 1532 different infrastructure. 1533 ` 1534 1535 const errBackendPlanStateFlag = ` 1536 The -state and -state-out flags cannot be set with a plan that has a remote 1537 state. The plan itself contains the configuration for the remote backend to 1538 store state. The state will be written there for consistency. 1539 1540 If you wish to change this behavior, please create a plan from local state. 1541 You may use the state flags with plans from local state to affect where 1542 the final state is written. 1543 ` 1544 1545 const errBackendPlanOlder = ` 1546 This plan was created against an older state than is current. Please create 1547 a new plan file against the latest state and try again. 1548 1549 Terraform doesn't allow you to run plans that were created from older 1550 states since it doesn't properly represent the latest changes Terraform 1551 may have made, and can result in unsafe behavior. 1552 1553 Plan Serial: %[1]d 1554 Current Serial: %[2]d 1555 ` 1556 1557 const outputBackendMigrateChange = ` 1558 Terraform detected that the backend type changed from %q to %q. 1559 ` 1560 1561 const outputBackendMigrateLegacy = ` 1562 Terraform detected legacy remote state. 1563 ` 1564 1565 const outputBackendMigrateLocal = ` 1566 Terraform has detected you're unconfiguring your previously set %q backend. 1567 ` 1568 1569 const outputBackendConfigureWithLegacy = ` 1570 [reset][bold]New backend configuration detected with legacy remote state![reset] 1571 1572 Terraform has detected that you're attempting to configure a new backend. 1573 At the same time, legacy remote state configuration was found. Terraform will 1574 first configure the new backend, and then ask if you'd like to migrate 1575 your remote state to the new backend. 1576 ` 1577 1578 const outputBackendReconfigure = ` 1579 [reset][bold]Backend configuration changed![reset] 1580 1581 Terraform has detected that the configuration specified for the backend 1582 has changed. Terraform will now check for existing state in the backends. 1583 ` 1584 1585 const outputBackendSavedWithLegacy = ` 1586 [reset][bold]Legacy remote state was detected![reset] 1587 1588 Terraform has detected you still have legacy remote state enabled while 1589 also having a backend configured. Terraform will now ask if you want to 1590 migrate your legacy remote state data to the configured backend. 1591 ` 1592 1593 const outputBackendSavedWithLegacyChanged = ` 1594 [reset][bold]Legacy remote state was detected while also changing your current backend!reset] 1595 1596 Terraform has detected that you have legacy remote state, a configured 1597 current backend, and you're attempting to reconfigure your backend. To handle 1598 all of these changes, Terraform will first reconfigure your backend. After 1599 this, Terraform will handle optionally copying your legacy remote state 1600 into the newly configured backend. 1601 ` 1602 1603 const outputBackendUnsetWithLegacy = ` 1604 [reset][bold]Detected a request to unset the backend with legacy remote state present![reset] 1605 1606 Terraform has detected that you're attempting to unset a previously configured 1607 backend (by not having the "backend" configuration set in your Terraform files). 1608 At the same time, legacy remote state was detected. To handle this complex 1609 scenario, Terraform will first unset your configured backend, and then 1610 ask you how to handle the legacy remote state. This will be multi-step 1611 process. 1612 ` 1613 1614 const successBackendLegacyUnset = ` 1615 Terraform has successfully migrated from legacy remote state to your 1616 configured backend (%q). 1617 ` 1618 1619 const successBackendReconfigureWithLegacy = ` 1620 Terraform has successfully reconfigured your backend and migrate 1621 from legacy remote state to the new backend. 1622 ` 1623 1624 const successBackendUnset = ` 1625 Successfully unset the backend %q. Terraform will now operate locally. 1626 ` 1627 1628 const successBackendSet = ` 1629 Successfully configured the backend %q! Terraform will automatically 1630 use this backend unless the backend configuration changes. 1631 ` 1632 1633 const warnBackendLegacy = ` 1634 Deprecation warning: This environment is configured to use legacy remote state. 1635 Remote state changed significantly in Terraform 0.9. Please update your remote 1636 state configuration to use the new 'backend' settings. For now, Terraform 1637 will continue to use your existing settings. Legacy remote state support 1638 will be removed in Terraform 0.11. 1639 1640 You can find a guide for upgrading here: 1641 1642 https://www.terraform.io/docs/backends/legacy-0-8.html 1643 `