github.com/nevins-b/terraform@v0.3.8-0.20170215184714-bbae22007d5a/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 clistate "github.com/hashicorp/terraform/command/state" 20 "github.com/hashicorp/terraform/config" 21 "github.com/hashicorp/terraform/state" 22 "github.com/hashicorp/terraform/terraform" 23 "github.com/mitchellh/mapstructure" 24 25 backendlegacy "github.com/hashicorp/terraform/backend/legacy" 26 backendlocal "github.com/hashicorp/terraform/backend/local" 27 backendconsul "github.com/hashicorp/terraform/backend/remote-state/consul" 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 err = clistate.Lock(realMgr, "backend from plan", m.Ui, m.Colorize()) 537 if err != nil { 538 return nil, fmt.Errorf("Error locking state: %s", err) 539 } 540 defer clistate.Unlock(realMgr, m.Ui, m.Colorize()) 541 542 if err := realMgr.RefreshState(); err != nil { 543 return nil, fmt.Errorf("Error reading state: %s", err) 544 } 545 real := realMgr.State() 546 if real != nil { 547 // If they're not the same lineage, don't allow this 548 if !real.SameLineage(planState) { 549 return nil, fmt.Errorf(strings.TrimSpace(errBackendPlanLineageDiff)) 550 } 551 552 // Compare ages 553 comp, err := real.CompareAges(planState) 554 if err != nil { 555 return nil, fmt.Errorf("Error comparing state ages for safety: %s", err) 556 } 557 switch comp { 558 case terraform.StateAgeEqual: 559 // State ages are equal, this is perfect 560 561 case terraform.StateAgeReceiverOlder: 562 // Real state is somehow older, this is okay. 563 564 case terraform.StateAgeReceiverNewer: 565 // If we have an older serial it is a problem but if we have a 566 // differing serial but are still identical, just let it through. 567 if real.Equal(planState) { 568 log.Printf( 569 "[WARN] command: state in plan has older serial, but Equal is true") 570 break 571 } 572 573 // The real state is newer, this is not allowed. 574 return nil, fmt.Errorf( 575 strings.TrimSpace(errBackendPlanOlder), 576 planState.Serial, real.Serial) 577 } 578 } 579 580 // Write the state 581 newState := opts.Plan.State.DeepCopy() 582 if newState != nil { 583 newState.Remote = nil 584 newState.Backend = nil 585 } 586 587 // realMgr locked above 588 if err := realMgr.WriteState(newState); err != nil { 589 return nil, fmt.Errorf("Error writing state: %s", err) 590 } 591 if err := realMgr.PersistState(); err != nil { 592 return nil, fmt.Errorf("Error writing state: %s", err) 593 } 594 595 return b, nil 596 } 597 598 //------------------------------------------------------------------- 599 // Backend Config Scenarios 600 // 601 // The functions below cover handling all the various scenarios that 602 // can exist when loading a backend. They are named in the format of 603 // "backend_C_R_S" where C, R, S may be upper or lowercase. Lowercase 604 // means it is false, uppercase means it is true. The full set of eight 605 // possible cases is handled. 606 // 607 // The fields are: 608 // 609 // * C - Backend configuration is set and changed in TF files 610 // * R - Legacy remote state is set 611 // * S - Backend configuration is set in the state 612 // 613 //------------------------------------------------------------------- 614 615 // Unconfiguring a backend (moving from backend => local). 616 func (m *Meta) backend_c_r_S( 617 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 618 s := sMgr.State() 619 620 // Get the backend type for output 621 backendType := s.Backend.Type 622 623 // Confirm with the user that the copy should occur 624 copy, err := m.confirm(&terraform.InputOpts{ 625 Id: "backend-migrate-to-local", 626 Query: fmt.Sprintf("Do you want to copy the state from %q?", s.Backend.Type), 627 Description: fmt.Sprintf( 628 strings.TrimSpace(inputBackendMigrateLocal), s.Backend.Type), 629 }) 630 if err != nil { 631 return nil, fmt.Errorf( 632 "Error asking for state copy action: %s", err) 633 } 634 635 // If we're copying, perform the migration 636 if copy { 637 // Grab a purely local backend to get the local state if it exists 638 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 639 if err != nil { 640 return nil, fmt.Errorf(strings.TrimSpace(errBackendLocalRead), err) 641 } 642 localState, err := localB.State() 643 if err != nil { 644 return nil, fmt.Errorf(strings.TrimSpace(errBackendLocalRead), err) 645 } 646 if err := localState.RefreshState(); err != nil { 647 return nil, fmt.Errorf(strings.TrimSpace(errBackendLocalRead), err) 648 } 649 650 // Initialize the configured backend 651 b, err := m.backend_C_r_S_unchanged(c, sMgr) 652 if err != nil { 653 return nil, fmt.Errorf( 654 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 655 } 656 backendState, err := b.State() 657 if err != nil { 658 return nil, fmt.Errorf( 659 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 660 } 661 if err := backendState.RefreshState(); err != nil { 662 return nil, fmt.Errorf( 663 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 664 } 665 666 // Perform the migration 667 err = m.backendMigrateState(&backendMigrateOpts{ 668 OneType: s.Backend.Type, 669 TwoType: "local", 670 One: backendState, 671 Two: localState, 672 }) 673 if err != nil { 674 return nil, err 675 } 676 } 677 678 // Remove the stored metadata 679 s.Backend = nil 680 if err := sMgr.WriteState(s); err != nil { 681 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err) 682 } 683 if err := sMgr.PersistState(); err != nil { 684 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err) 685 } 686 687 if output { 688 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 689 "[reset][green]\n\n"+ 690 strings.TrimSpace(successBackendUnset), backendType))) 691 } 692 693 // Return no backend 694 return nil, nil 695 } 696 697 // Legacy remote state 698 func (m *Meta) backend_c_R_s( 699 c *config.Backend, sMgr state.State) (backend.Backend, error) { 700 s := sMgr.State() 701 702 // Warn the user 703 m.Ui.Warn(strings.TrimSpace(warnBackendLegacy) + "\n") 704 705 // We need to convert the config to map[string]interface{} since that 706 // is what the backends expect. 707 var configMap map[string]interface{} 708 if err := mapstructure.Decode(s.Remote.Config, &configMap); err != nil { 709 return nil, fmt.Errorf("Error configuring remote state: %s", err) 710 } 711 712 // Create the config 713 rawC, err := config.NewRawConfig(configMap) 714 if err != nil { 715 return nil, fmt.Errorf("Error configuring remote state: %s", err) 716 } 717 config := terraform.NewResourceConfig(rawC) 718 719 // Initialize the legacy remote backend 720 b := &backendlegacy.Backend{Type: s.Remote.Type} 721 722 // Configure 723 if err := b.Configure(config); err != nil { 724 return nil, fmt.Errorf(errBackendLegacyConfig, err) 725 } 726 727 return b, nil 728 } 729 730 // Unsetting backend, saved backend, legacy remote state 731 func (m *Meta) backend_c_R_S( 732 c *config.Backend, sMgr state.State) (backend.Backend, error) { 733 // Notify the user 734 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 735 "[reset]%s\n\n", 736 strings.TrimSpace(outputBackendUnsetWithLegacy)))) 737 738 // Get the backend type for later 739 backendType := sMgr.State().Backend.Type 740 741 // First, perform the configured => local tranasition 742 if _, err := m.backend_c_r_S(c, sMgr, false); err != nil { 743 return nil, err 744 } 745 746 // Grab a purely local backend 747 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 748 if err != nil { 749 return nil, fmt.Errorf(errBackendLocalRead, err) 750 } 751 localState, err := localB.State() 752 if err != nil { 753 return nil, fmt.Errorf(errBackendLocalRead, err) 754 } 755 if err := localState.RefreshState(); err != nil { 756 return nil, fmt.Errorf(errBackendLocalRead, err) 757 } 758 759 // Grab the state 760 s := sMgr.State() 761 762 // Ask the user if they want to migrate their existing remote state 763 copy, err := m.confirm(&terraform.InputOpts{ 764 Id: "backend-migrate-to-new", 765 Query: fmt.Sprintf( 766 "Do you want to copy the legacy remote state from %q?", 767 s.Remote.Type), 768 Description: strings.TrimSpace(inputBackendMigrateLegacyLocal), 769 }) 770 if err != nil { 771 return nil, fmt.Errorf( 772 "Error asking for state copy action: %s", err) 773 } 774 775 // If the user wants a copy, copy! 776 if copy { 777 // Initialize the legacy backend 778 oldB, err := m.backendInitFromLegacy(s.Remote) 779 if err != nil { 780 return nil, err 781 } 782 oldState, err := oldB.State() 783 if err != nil { 784 return nil, fmt.Errorf( 785 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 786 } 787 if err := oldState.RefreshState(); err != nil { 788 return nil, fmt.Errorf( 789 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 790 } 791 792 // Perform the migration 793 err = m.backendMigrateState(&backendMigrateOpts{ 794 OneType: s.Remote.Type, 795 TwoType: "local", 796 One: oldState, 797 Two: localState, 798 }) 799 if err != nil { 800 return nil, err 801 } 802 } 803 804 // Unset the remote state 805 s = sMgr.State() 806 if s == nil { 807 s = terraform.NewState() 808 } 809 s.Remote = nil 810 if err := sMgr.WriteState(s); err != nil { 811 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 812 } 813 if err := sMgr.PersistState(); err != nil { 814 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 815 } 816 817 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 818 "[reset][green]\n\n"+ 819 strings.TrimSpace(successBackendUnset), backendType))) 820 821 return nil, nil 822 } 823 824 // Configuring a backend for the first time with legacy remote state. 825 func (m *Meta) backend_C_R_s( 826 c *config.Backend, sMgr state.State) (backend.Backend, error) { 827 // Notify the user 828 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 829 "[reset]%s\n\n", 830 strings.TrimSpace(outputBackendConfigureWithLegacy)))) 831 832 // First, configure the new backend 833 b, err := m.backendInitFromConfig(c) 834 if err != nil { 835 return nil, err 836 } 837 838 // Next, save the new configuration. This will not overwrite our 839 // legacy remote state. We'll handle that after. 840 s := sMgr.State() 841 if s == nil { 842 s = terraform.NewState() 843 } 844 s.Backend = &terraform.BackendState{ 845 Type: c.Type, 846 Config: c.RawConfig.Raw, 847 Hash: c.Hash, 848 } 849 if err := sMgr.WriteState(s); err != nil { 850 return nil, fmt.Errorf(errBackendWriteSaved, err) 851 } 852 if err := sMgr.PersistState(); err != nil { 853 return nil, fmt.Errorf(errBackendWriteSaved, err) 854 } 855 856 // I don't know how this is possible but if we don't have remote 857 // state config anymore somehow, just return the backend. This 858 // shouldn't be possible, though. 859 if s.Remote.Empty() { 860 return b, nil 861 } 862 863 // Finally, ask the user if they want to copy the state from 864 // their old remote state location. 865 copy, err := m.confirm(&terraform.InputOpts{ 866 Id: "backend-migrate-to-new", 867 Query: fmt.Sprintf( 868 "Do you want to copy the legacy remote state from %q?", 869 s.Remote.Type), 870 Description: strings.TrimSpace(inputBackendMigrateLegacy), 871 }) 872 if err != nil { 873 return nil, fmt.Errorf( 874 "Error asking for state copy action: %s", err) 875 } 876 877 // If the user wants a copy, copy! 878 if copy { 879 // Initialize the legacy backend 880 oldB, err := m.backendInitFromLegacy(s.Remote) 881 if err != nil { 882 return nil, err 883 } 884 oldState, err := oldB.State() 885 if err != nil { 886 return nil, fmt.Errorf( 887 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 888 } 889 if err := oldState.RefreshState(); err != nil { 890 return nil, fmt.Errorf( 891 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 892 } 893 894 // Get the new state 895 newState, err := b.State() 896 if err != nil { 897 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewRead), err) 898 } 899 if err := newState.RefreshState(); err != nil { 900 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewRead), err) 901 } 902 903 // Perform the migration 904 err = m.backendMigrateState(&backendMigrateOpts{ 905 OneType: s.Remote.Type, 906 TwoType: c.Type, 907 One: oldState, 908 Two: newState, 909 }) 910 if err != nil { 911 return nil, err 912 } 913 } 914 915 // Unset the remote state 916 s = sMgr.State() 917 if s == nil { 918 s = terraform.NewState() 919 } 920 s.Remote = nil 921 if err := sMgr.WriteState(s); err != nil { 922 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 923 } 924 if err := sMgr.PersistState(); err != nil { 925 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 926 } 927 928 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 929 "[reset][green]\n\n"+ 930 strings.TrimSpace(successBackendSet), s.Backend.Type))) 931 932 return b, nil 933 } 934 935 // Configuring a backend for the first time. 936 func (m *Meta) backend_C_r_s( 937 c *config.Backend, sMgr state.State) (backend.Backend, error) { 938 // Get the backend 939 b, err := m.backendInitFromConfig(c) 940 if err != nil { 941 return nil, err 942 } 943 944 // Grab a purely local backend to get the local state if it exists 945 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 946 if err != nil { 947 return nil, fmt.Errorf(errBackendLocalRead, err) 948 } 949 localState, err := localB.State() 950 if err != nil { 951 return nil, fmt.Errorf(errBackendLocalRead, err) 952 } 953 if err := localState.RefreshState(); err != nil { 954 return nil, fmt.Errorf(errBackendLocalRead, err) 955 } 956 957 // If the local state is not empty, we need to potentially do a 958 // state migration to the new backend (with user permission). 959 if localS := localState.State(); !localS.Empty() { 960 backendState, err := b.State() 961 if err != nil { 962 return nil, fmt.Errorf(errBackendRemoteRead, err) 963 } 964 if err := backendState.RefreshState(); err != nil { 965 return nil, fmt.Errorf(errBackendRemoteRead, err) 966 } 967 968 // Perform the migration 969 err = m.backendMigrateState(&backendMigrateOpts{ 970 OneType: "local", 971 TwoType: c.Type, 972 One: localState, 973 Two: backendState, 974 }) 975 if err != nil { 976 return nil, err 977 } 978 979 // We always delete the local state 980 if err := localState.WriteState(nil); err != nil { 981 return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) 982 } 983 if err := localState.PersistState(); err != nil { 984 return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) 985 } 986 } 987 988 // Lock the state if we can 989 err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize()) 990 if err != nil { 991 return nil, fmt.Errorf("Error locking state: %s", err) 992 } 993 defer clistate.Unlock(sMgr, m.Ui, m.Colorize()) 994 995 // Store the metadata in our saved state location 996 s := sMgr.State() 997 if s == nil { 998 s = terraform.NewState() 999 } 1000 s.Backend = &terraform.BackendState{ 1001 Type: c.Type, 1002 Config: c.RawConfig.Raw, 1003 Hash: c.Hash, 1004 } 1005 1006 if err := sMgr.WriteState(s); err != nil { 1007 return nil, fmt.Errorf(errBackendWriteSaved, err) 1008 } 1009 if err := sMgr.PersistState(); err != nil { 1010 return nil, fmt.Errorf(errBackendWriteSaved, err) 1011 } 1012 1013 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1014 "[reset][green]\n\n"+ 1015 strings.TrimSpace(successBackendSet), s.Backend.Type))) 1016 1017 // Return the backend 1018 return b, nil 1019 } 1020 1021 // Changing a previously saved backend. 1022 func (m *Meta) backend_C_r_S_changed( 1023 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 1024 if output { 1025 // Notify the user 1026 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1027 "[reset]%s\n\n", 1028 strings.TrimSpace(outputBackendReconfigure)))) 1029 } 1030 1031 // Get the old state 1032 s := sMgr.State() 1033 1034 // Get the backend 1035 b, err := m.backendInitFromConfig(c) 1036 if err != nil { 1037 return nil, fmt.Errorf( 1038 "Error initializing new backend: %s", err) 1039 } 1040 1041 // Check with the user if we want to migrate state 1042 copy, err := m.confirm(&terraform.InputOpts{ 1043 Id: "backend-migrate-to-new", 1044 Query: fmt.Sprintf("Do you want to copy the state from %q?", c.Type), 1045 Description: strings.TrimSpace(fmt.Sprintf(inputBackendMigrateChange, c.Type, s.Backend.Type)), 1046 }) 1047 if err != nil { 1048 return nil, fmt.Errorf( 1049 "Error asking for state copy action: %s", err) 1050 } 1051 1052 // If we are, then we need to initialize the old backend and 1053 // perform the copy. 1054 if copy { 1055 // Grab the existing backend 1056 oldB, err := m.backend_C_r_S_unchanged(c, sMgr) 1057 if err != nil { 1058 return nil, fmt.Errorf( 1059 "Error loading previously configured backend: %s", err) 1060 } 1061 1062 oldState, err := oldB.State() 1063 if err != nil { 1064 return nil, fmt.Errorf( 1065 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 1066 } 1067 if err := oldState.RefreshState(); err != nil { 1068 return nil, fmt.Errorf( 1069 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 1070 } 1071 1072 // Get the new state 1073 newState, err := b.State() 1074 if err != nil { 1075 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewRead), err) 1076 } 1077 if err := newState.RefreshState(); err != nil { 1078 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewRead), err) 1079 } 1080 1081 // Perform the migration 1082 err = m.backendMigrateState(&backendMigrateOpts{ 1083 OneType: s.Backend.Type, 1084 TwoType: c.Type, 1085 One: oldState, 1086 Two: newState, 1087 }) 1088 if err != nil { 1089 return nil, err 1090 } 1091 } 1092 1093 // Lock the state if we can 1094 err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize()) 1095 if err != nil { 1096 return nil, fmt.Errorf("Error locking state: %s", err) 1097 } 1098 defer clistate.Unlock(sMgr, m.Ui, m.Colorize()) 1099 1100 // Update the backend state 1101 s = sMgr.State() 1102 if s == nil { 1103 s = terraform.NewState() 1104 } 1105 s.Backend = &terraform.BackendState{ 1106 Type: c.Type, 1107 Config: c.RawConfig.Raw, 1108 Hash: c.Hash, 1109 } 1110 1111 if err := sMgr.WriteState(s); err != nil { 1112 return nil, fmt.Errorf(errBackendWriteSaved, err) 1113 } 1114 if err := sMgr.PersistState(); err != nil { 1115 return nil, fmt.Errorf(errBackendWriteSaved, err) 1116 } 1117 1118 if output { 1119 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1120 "[reset][green]\n\n"+ 1121 strings.TrimSpace(successBackendSet), s.Backend.Type))) 1122 } 1123 1124 return b, nil 1125 } 1126 1127 // Initiailizing an unchanged saved backend 1128 func (m *Meta) backend_C_r_S_unchanged( 1129 c *config.Backend, sMgr state.State) (backend.Backend, error) { 1130 s := sMgr.State() 1131 1132 // Create the config. We do this from the backend state since this 1133 // has the complete configuration data whereas the config itself 1134 // may require input. 1135 rawC, err := config.NewRawConfig(s.Backend.Config) 1136 if err != nil { 1137 return nil, fmt.Errorf("Error configuring backend: %s", err) 1138 } 1139 config := terraform.NewResourceConfig(rawC) 1140 1141 // Get the backend 1142 f, ok := Backends[s.Backend.Type] 1143 if !ok { 1144 return nil, fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type) 1145 } 1146 b := f() 1147 1148 // Configure 1149 if err := b.Configure(config); err != nil { 1150 return nil, fmt.Errorf(errBackendSavedConfig, s.Backend.Type, err) 1151 } 1152 1153 return b, nil 1154 } 1155 1156 // Initiailizing a changed saved backend with legacy remote state. 1157 func (m *Meta) backend_C_R_S_changed( 1158 c *config.Backend, sMgr state.State) (backend.Backend, error) { 1159 // Notify the user 1160 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1161 "[reset]%s\n\n", 1162 strings.TrimSpace(outputBackendSavedWithLegacyChanged)))) 1163 1164 // Reconfigure the backend first 1165 if _, err := m.backend_C_r_S_changed(c, sMgr, false); err != nil { 1166 return nil, err 1167 } 1168 1169 // Handle the case where we have all set but unchanged 1170 b, err := m.backend_C_R_S_unchanged(c, sMgr, false) 1171 if err != nil { 1172 return nil, err 1173 } 1174 1175 // Output success message 1176 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1177 "[reset][green]\n\n"+ 1178 strings.TrimSpace(successBackendReconfigureWithLegacy), c.Type))) 1179 1180 return b, nil 1181 } 1182 1183 // Initiailizing an unchanged saved backend with legacy remote state. 1184 func (m *Meta) backend_C_R_S_unchanged( 1185 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 1186 if output { 1187 // Notify the user 1188 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1189 "[reset]%s\n\n", 1190 strings.TrimSpace(outputBackendSavedWithLegacy)))) 1191 } 1192 1193 // Load the backend from the state 1194 s := sMgr.State() 1195 b, err := m.backendInitFromSaved(s.Backend) 1196 if err != nil { 1197 return nil, err 1198 } 1199 1200 // Ask if the user wants to move their legacy remote state 1201 copy, err := m.confirm(&terraform.InputOpts{ 1202 Id: "backend-migrate-to-new", 1203 Query: fmt.Sprintf( 1204 "Do you want to copy the legacy remote state from %q?", 1205 s.Remote.Type), 1206 Description: strings.TrimSpace(inputBackendMigrateLegacy), 1207 }) 1208 if err != nil { 1209 return nil, fmt.Errorf( 1210 "Error asking for state copy action: %s", err) 1211 } 1212 1213 // If the user wants a copy, copy! 1214 if copy { 1215 // Initialize the legacy backend 1216 oldB, err := m.backendInitFromLegacy(s.Remote) 1217 if err != nil { 1218 return nil, err 1219 } 1220 oldState, err := oldB.State() 1221 if err != nil { 1222 return nil, fmt.Errorf( 1223 strings.TrimSpace(errBackendSavedUnsetConfig), s.Remote.Type, err) 1224 } 1225 if err := oldState.RefreshState(); err != nil { 1226 return nil, fmt.Errorf( 1227 strings.TrimSpace(errBackendSavedUnsetConfig), s.Remote.Type, err) 1228 } 1229 1230 // Get the new state 1231 newState, err := b.State() 1232 if err != nil { 1233 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewRead), err) 1234 } 1235 if err := newState.RefreshState(); err != nil { 1236 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewRead), err) 1237 } 1238 1239 // Perform the migration 1240 err = m.backendMigrateState(&backendMigrateOpts{ 1241 OneType: s.Remote.Type, 1242 TwoType: s.Backend.Type, 1243 One: oldState, 1244 Two: newState, 1245 }) 1246 if err != nil { 1247 return nil, err 1248 } 1249 } 1250 1251 // Lock the state if we can 1252 err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize()) 1253 if err != nil { 1254 return nil, fmt.Errorf("Error locking state: %s", err) 1255 } 1256 defer clistate.Unlock(sMgr, m.Ui, m.Colorize()) 1257 1258 // Unset the remote state 1259 s = sMgr.State() 1260 if s == nil { 1261 s = terraform.NewState() 1262 } 1263 s.Remote = nil 1264 1265 if err := sMgr.WriteState(s); err != nil { 1266 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 1267 } 1268 if err := sMgr.PersistState(); err != nil { 1269 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 1270 } 1271 1272 if output { 1273 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1274 "[reset][green]\n\n"+ 1275 strings.TrimSpace(successBackendLegacyUnset), s.Backend.Type))) 1276 } 1277 1278 return b, nil 1279 } 1280 1281 //------------------------------------------------------------------- 1282 // Reusable helper functions for backend management 1283 //------------------------------------------------------------------- 1284 1285 func (m *Meta) backendInitFromConfig(c *config.Backend) (backend.Backend, error) { 1286 // Create the config. 1287 config := terraform.NewResourceConfig(c.RawConfig) 1288 1289 // Get the backend 1290 f, ok := Backends[c.Type] 1291 if !ok { 1292 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewUnknown), c.Type) 1293 } 1294 b := f() 1295 1296 // TODO: test 1297 // Ask for input if we have input enabled 1298 if m.Input() { 1299 var err error 1300 config, err = b.Input(m.UIInput(), config) 1301 if err != nil { 1302 return nil, fmt.Errorf( 1303 "Error asking for input to configure the backend %q: %s", 1304 c.Type, err) 1305 } 1306 } 1307 1308 // Validate 1309 warns, errs := b.Validate(config) 1310 if len(errs) > 0 { 1311 return nil, fmt.Errorf( 1312 "Error configuring the backend %q: %s", 1313 c.Type, multierror.Append(nil, errs...)) 1314 } 1315 if len(warns) > 0 { 1316 // TODO: warnings are currently ignored 1317 } 1318 1319 // Configure 1320 if err := b.Configure(config); err != nil { 1321 return nil, fmt.Errorf(errBackendNewConfig, c.Type, err) 1322 } 1323 1324 return b, nil 1325 } 1326 1327 func (m *Meta) backendInitFromLegacy(s *terraform.RemoteState) (backend.Backend, error) { 1328 // We need to convert the config to map[string]interface{} since that 1329 // is what the backends expect. 1330 var configMap map[string]interface{} 1331 if err := mapstructure.Decode(s.Config, &configMap); err != nil { 1332 return nil, fmt.Errorf("Error configuring remote state: %s", err) 1333 } 1334 1335 // Create the config 1336 rawC, err := config.NewRawConfig(configMap) 1337 if err != nil { 1338 return nil, fmt.Errorf("Error configuring remote state: %s", err) 1339 } 1340 config := terraform.NewResourceConfig(rawC) 1341 1342 // Initialize the legacy remote backend 1343 b := &backendlegacy.Backend{Type: s.Type} 1344 1345 // Configure 1346 if err := b.Configure(config); err != nil { 1347 return nil, fmt.Errorf(errBackendLegacyConfig, err) 1348 } 1349 1350 return b, nil 1351 } 1352 1353 func (m *Meta) backendInitFromSaved(s *terraform.BackendState) (backend.Backend, error) { 1354 // Create the config. We do this from the backend state since this 1355 // has the complete configuration data whereas the config itself 1356 // may require input. 1357 rawC, err := config.NewRawConfig(s.Config) 1358 if err != nil { 1359 return nil, fmt.Errorf("Error configuring backend: %s", err) 1360 } 1361 config := terraform.NewResourceConfig(rawC) 1362 1363 // Get the backend 1364 f, ok := Backends[s.Type] 1365 if !ok { 1366 return nil, fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Type) 1367 } 1368 b := f() 1369 1370 // Configure 1371 if err := b.Configure(config); err != nil { 1372 return nil, fmt.Errorf(errBackendSavedConfig, s.Type, err) 1373 } 1374 1375 return b, nil 1376 } 1377 1378 func (m *Meta) backendInitRequired(reason string) { 1379 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1380 "[reset]"+strings.TrimSpace(errBackendInit)+"\n", reason))) 1381 } 1382 1383 //------------------------------------------------------------------- 1384 // Output constants and initialization code 1385 //------------------------------------------------------------------- 1386 1387 // Backends is the list of available backends. This is currently a hardcoded 1388 // list that can't be modified without recompiling Terraform. This is done 1389 // because the API for backends uses complex structures and supporting that 1390 // over the plugin system is currently prohibitively difficult. For those 1391 // wanting to implement a custom backend, recompilation should not be a 1392 // high barrier. 1393 var Backends map[string]func() backend.Backend 1394 1395 func init() { 1396 // Our hardcoded backends 1397 Backends = map[string]func() backend.Backend{ 1398 "local": func() backend.Backend { return &backendlocal.Local{} }, 1399 "consul": func() backend.Backend { return backendconsul.New() }, 1400 } 1401 1402 // Add the legacy remote backends that haven't yet been convertd to 1403 // the new backend API. 1404 backendlegacy.Init(Backends) 1405 } 1406 1407 // errBackendInitRequired is the final error message shown when reinit 1408 // is required for some reason. The error message includes the reason. 1409 var errBackendInitRequired = errors.New( 1410 "Initialization required. Please see the error message above.") 1411 1412 const errBackendLegacyConfig = ` 1413 One or more errors occurred while configuring the legacy remote state. 1414 If fixing these errors requires changing your remote state configuration, 1415 you must switch your configuration to the new remote backend configuration. 1416 You can learn more about remote backends at the URL below: 1417 1418 TODO: URL 1419 1420 The error(s) configuring the legacy remote state: 1421 1422 %s 1423 ` 1424 1425 const errBackendLocalRead = ` 1426 Error reading local state: %s 1427 1428 Terraform is trying to read your local state to determine if there is 1429 state to migrate to your newly configured backend. Terraform can't continue 1430 without this check because that would risk losing state. Please resolve the 1431 error above and try again. 1432 ` 1433 1434 const errBackendMigrateLocalDelete = ` 1435 Error deleting local state after migration: %s 1436 1437 Your local state is deleted after successfully migrating it to the newly 1438 configured backend. As part of the deletion process, a backup is made at 1439 the standard backup path unless explicitly asked not to. To cleanly operate 1440 with a backend, we must delete the local state file. Please resolve the 1441 issue above and retry the command. 1442 ` 1443 1444 const errBackendMigrateNew = ` 1445 Error migrating local state to backend: %s 1446 1447 Your local state remains intact and unmodified. Please resolve the error 1448 above and try again. 1449 ` 1450 1451 const errBackendNewConfig = ` 1452 Error configuring the backend %q: %s 1453 1454 Please update the configuration in your Terraform files to fix this error 1455 then run this command again. 1456 ` 1457 1458 const errBackendNewRead = ` 1459 Error reading newly configured backend state: %s 1460 1461 Terraform is trying to read the state from your newly configured backend 1462 to determine the copy process for your existing state. Backends are expected 1463 to not error even if there is no state yet written. Please resolve the 1464 error above and try again. 1465 ` 1466 1467 const errBackendNewUnknown = ` 1468 The backend %q could not be found. 1469 1470 This is the backend specified in your Terraform configuration file. 1471 This error could be a simple typo in your configuration, but it can also 1472 be caused by using a Terraform version that doesn't support the specified 1473 backend type. Please check your configuration and your Terraform version. 1474 1475 If you'd like to run Terraform and store state locally, you can fix this 1476 error by removing the backend configuration from your configuration. 1477 ` 1478 1479 const errBackendRemoteRead = ` 1480 Error reading backend state: %s 1481 1482 Terraform is trying to read the state from your configured backend to 1483 determine if there is any migration steps necessary. Terraform can't continue 1484 without this check because that would risk losing state. Please resolve the 1485 error above and try again. 1486 ` 1487 1488 const errBackendSavedConfig = ` 1489 Error configuring the backend %q: %s 1490 1491 Please update the configuration in your Terraform files to fix this error. 1492 If you'd like to update the configuration interactively without storing 1493 the values in your configuration, run "terraform init". 1494 ` 1495 1496 const errBackendSavedUnsetConfig = ` 1497 Error configuring the existing backend %q: %s 1498 1499 Terraform must configure the existing backend in order to copy the state 1500 from the existing backend, as requested. Please resolve the error and try 1501 again. If you choose to not copy the existing state, Terraform will not 1502 configure the backend. If the configuration is invalid, please update your 1503 Terraform configuration with proper configuration for this backend first 1504 before unsetting the backend. 1505 ` 1506 1507 const errBackendSavedUnknown = ` 1508 The backend %q could not be found. 1509 1510 This is the backend that this Terraform environment is configured to use 1511 both in your configuration and saved locally as your last-used backend. 1512 If it isn't found, it could mean an alternate version of Terraform was 1513 used with this configuration. Please use the proper version of Terraform that 1514 contains support for this backend. 1515 1516 If you'd like to force remove this backend, you must update your configuration 1517 to not use the backend and run "terraform init" (or any other command) again. 1518 ` 1519 1520 const errBackendClearLegacy = ` 1521 Error clearing the legacy remote state configuration: %s 1522 1523 Terraform completed configuring your backend. It is now safe to remove 1524 the legacy remote state configuration, but an error occurred while trying 1525 to do so. Please look at the error above, resolve it, and try again. 1526 ` 1527 1528 const errBackendClearSaved = ` 1529 Error clearing the backend configuration: %s 1530 1531 Terraform removes the saved backend configuration when you're removing a 1532 configured backend. This must be done so future Terraform runs know to not 1533 use the backend configuration. Please look at the error above, resolve it, 1534 and try again. 1535 ` 1536 1537 const errBackendInit = ` 1538 [reset][bold][yellow]Backend reinitialization required. Please run "terraform init".[reset] 1539 [yellow]Reason: %s 1540 1541 The "backend" is the interface that Terraform uses to store state, 1542 perform operations, etc. If this message is showing up, it means that the 1543 Terraform configuration you're using is using a custom configuration for 1544 the Terraform backend. 1545 1546 Changes to backend configurations require reinitialization. This allows 1547 Terraform to setup the new configuration, copy existing state, etc. This is 1548 only done during "terraform init". Please run that command now then try again. 1549 1550 If the change reason above is incorrect, please verify your configuration 1551 hasn't changed and try again. At this point, no changes to your existing 1552 configuration or state have been made. 1553 ` 1554 1555 const errBackendWriteSaved = ` 1556 Error saving the backend configuration: %s 1557 1558 Terraform saves the complete backend configuration in a local file for 1559 configuring the backend on future operations. This cannot be disabled. Errors 1560 are usually due to simple file permission errors. Please look at the error 1561 above, resolve it, and try again. 1562 ` 1563 1564 const errBackendPlanBoth = ` 1565 The plan file contained both a legacy remote state and backend configuration. 1566 This is not allowed. Please recreate the plan file with the latest version of 1567 Terraform. 1568 ` 1569 1570 const errBackendPlanLineageDiff = ` 1571 The plan file contains a state with a differing lineage than the current 1572 state. By continuing, your current state would be overwritten by the state 1573 in the plan. Please either update the plan with the latest state or delete 1574 your current state and try again. 1575 1576 "Lineage" is a unique identifier generated only once on the creation of 1577 a new, empty state. If these values differ, it means they were created new 1578 at different times. Therefore, Terraform must assume that they're completely 1579 different states. 1580 1581 The most common cause of seeing this error is using a plan that was 1582 created against a different state. Perhaps the plan is very old and the 1583 state has since been recreated, or perhaps the plan was against a competely 1584 different infrastructure. 1585 ` 1586 1587 const errBackendPlanStateFlag = ` 1588 The -state and -state-out flags cannot be set with a plan that has a remote 1589 state. The plan itself contains the configuration for the remote backend to 1590 store state. The state will be written there for consistency. 1591 1592 If you wish to change this behavior, please create a plan from local state. 1593 You may use the state flags with plans from local state to affect where 1594 the final state is written. 1595 ` 1596 1597 const errBackendPlanOlder = ` 1598 This plan was created against an older state than is current. Please create 1599 a new plan file against the latest state and try again. 1600 1601 Terraform doesn't allow you to run plans that were created from older 1602 states since it doesn't properly represent the latest changes Terraform 1603 may have made, and can result in unsafe behavior. 1604 1605 Plan Serial: %[1]d 1606 Current Serial: %[2]d 1607 ` 1608 1609 const inputBackendMigrateChange = ` 1610 Would you like to copy the state from your prior backend %q to the 1611 newly configured %q backend? If you're reconfiguring the same backend, 1612 answering "yes" or "no" shouldn't make a difference. Please answer exactly 1613 "yes" or "no". 1614 ` 1615 1616 const inputBackendMigrateLegacy = ` 1617 Terraform can copy the existing state in your legacy remote state 1618 backend to your newly configured backend. Please answer "yes" or "no". 1619 ` 1620 1621 const inputBackendMigrateLegacyLocal = ` 1622 Terraform can copy the existing state in your legacy remote state 1623 backend to your local state. Please answer "yes" or "no". 1624 ` 1625 1626 const inputBackendMigrateLocal = ` 1627 Terraform has detected you're unconfiguring your previously set backend. 1628 Would you like to copy the state from %q to local state? Please answer 1629 "yes" or "no". If you answer "no", you will start with a blank local state. 1630 ` 1631 1632 const outputBackendConfigureWithLegacy = ` 1633 [reset][bold]New backend configuration detected with legacy remote state![reset] 1634 1635 Terraform has detected that you're attempting to configure a new backend. 1636 At the same time, legacy remote state configuration was found. Terraform will 1637 first configure the new backend, and then ask if you'd like to migrate 1638 your remote state to the new backend. 1639 ` 1640 1641 const outputBackendReconfigure = ` 1642 [reset][bold]Backend configuration changed![reset] 1643 1644 Terraform has detected that the configuration specified for the backend 1645 has changed. Terraform will now reconfigure for this backend. If you didn't 1646 intend to reconfigure your backend please undo any changes to the "backend" 1647 section in your Terraform configuration. 1648 ` 1649 1650 const outputBackendSavedWithLegacy = ` 1651 [reset][bold]Legacy remote state was detected![reset] 1652 1653 Terraform has detected you still have legacy remote state enabled while 1654 also having a backend configured. Terraform will now ask if you want to 1655 migrate your legacy remote state data to the configured backend. 1656 ` 1657 1658 const outputBackendSavedWithLegacyChanged = ` 1659 [reset][bold]Legacy remote state was detected while also changing your current backend!reset] 1660 1661 Terraform has detected that you have legacy remote state, a configured 1662 current backend, and you're attempting to reconfigure your backend. To handle 1663 all of these changes, Terraform will first reconfigure your backend. After 1664 this, Terraform will handle optionally copying your legacy remote state 1665 into the newly configured backend. 1666 ` 1667 1668 const outputBackendUnsetWithLegacy = ` 1669 [reset][bold]Detected a request to unset the backend with legacy remote state present![reset] 1670 1671 Terraform has detected that you're attempting to unset a previously configured 1672 backend (by not having the "backend" configuration set in your Terraform files). 1673 At the same time, legacy remote state was detected. To handle this complex 1674 scenario, Terraform will first unset your configured backend, and then 1675 ask you how to handle the legacy remote state. This will be multi-step 1676 process. 1677 ` 1678 1679 const successBackendLegacyUnset = ` 1680 Terraform has successfully migrated from legacy remote state to your 1681 configured remote state. 1682 ` 1683 1684 const successBackendReconfigureWithLegacy = ` 1685 Terraform has successfully reconfigured your backend and migrate 1686 from legacy remote state to the new backend. 1687 ` 1688 1689 const successBackendUnset = ` 1690 Successfully unset the backend %q. Terraform will now operate locally. 1691 ` 1692 1693 const successBackendSet = ` 1694 Successfully configured the backend %q! Terraform will automatically 1695 use this backend unless the backend configuration changes. 1696 ` 1697 1698 const warnBackendLegacy = ` 1699 Deprecation warning: This environment is configured to use legacy remote state. 1700 Remote state changed significantly in Terraform 0.9. Please update your remote 1701 state configuration to use the new 'backend' settings. For now, Terraform 1702 will continue to use your existing settings. Legacy remote state support 1703 will be removed in Terraform 0.11. 1704 `