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