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