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