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