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