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