github.com/vic3lord/terraform@v0.8.0-rc1.0.20170626102919-16c6dd2cb372/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"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 950 951 return b, nil 952 } 953 954 // Configuring a backend for the first time. 955 func (m *Meta) backend_C_r_s( 956 c *config.Backend, sMgr state.State) (backend.Backend, error) { 957 // Get the backend 958 b, err := m.backendInitFromConfig(c) 959 if err != nil { 960 return nil, err 961 } 962 963 // Grab a purely local backend to get the local state if it exists 964 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 965 if err != nil { 966 return nil, fmt.Errorf(errBackendLocalRead, err) 967 } 968 969 env := m.Workspace() 970 971 localState, err := localB.State(env) 972 if err != nil { 973 return nil, fmt.Errorf(errBackendLocalRead, err) 974 } 975 if err := localState.RefreshState(); err != nil { 976 return nil, fmt.Errorf(errBackendLocalRead, err) 977 } 978 979 // If the local state is not empty, we need to potentially do a 980 // state migration to the new backend (with user permission), unless the 981 // destination is also "local" 982 if localS := localState.State(); !localS.Empty() { 983 // Perform the migration 984 err = m.backendMigrateState(&backendMigrateOpts{ 985 OneType: "local", 986 TwoType: c.Type, 987 One: localB, 988 Two: b, 989 }) 990 if err != nil { 991 return nil, err 992 } 993 994 // we usually remove the local state after migration to prevent 995 // confusion, but adding a default local backend block to the config 996 // can get us here too. Don't delete our state if the old and new paths 997 // are the same. 998 erase := true 999 if newLocalB, ok := b.(*backendlocal.Local); ok { 1000 if localB, ok := localB.(*backendlocal.Local); ok { 1001 if newLocalB.StatePath == localB.StatePath { 1002 erase = false 1003 } 1004 } 1005 } 1006 1007 if erase { 1008 // We always delete the local state, unless that was our new state too. 1009 if err := localState.WriteState(nil); err != nil { 1010 return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) 1011 } 1012 if err := localState.PersistState(); err != nil { 1013 return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) 1014 } 1015 } 1016 } 1017 1018 if m.stateLock { 1019 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 1020 defer cancel() 1021 1022 // Lock the state if we can 1023 lockInfo := state.NewLockInfo() 1024 lockInfo.Operation = "backend from config" 1025 1026 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 1027 if err != nil { 1028 return nil, fmt.Errorf("Error locking state: %s", err) 1029 } 1030 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 1031 } 1032 1033 // Store the metadata in our saved state location 1034 s := sMgr.State() 1035 if s == nil { 1036 s = terraform.NewState() 1037 } 1038 s.Backend = &terraform.BackendState{ 1039 Type: c.Type, 1040 Config: c.RawConfig.Raw, 1041 Hash: c.Hash, 1042 } 1043 1044 if err := sMgr.WriteState(s); err != nil { 1045 return nil, fmt.Errorf(errBackendWriteSaved, err) 1046 } 1047 if err := sMgr.PersistState(); err != nil { 1048 return nil, fmt.Errorf(errBackendWriteSaved, err) 1049 } 1050 1051 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1052 "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 1053 1054 // Return the backend 1055 return b, nil 1056 } 1057 1058 // Changing a previously saved backend. 1059 func (m *Meta) backend_C_r_S_changed( 1060 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 1061 if output { 1062 // Notify the user 1063 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1064 "[reset]%s\n\n", 1065 strings.TrimSpace(outputBackendReconfigure)))) 1066 } 1067 1068 // Get the old state 1069 s := sMgr.State() 1070 1071 // Get the backend 1072 b, err := m.backendInitFromConfig(c) 1073 if err != nil { 1074 return nil, fmt.Errorf( 1075 "Error initializing new backend: %s", err) 1076 } 1077 1078 // Check with the user if we want to migrate state 1079 copy := m.forceInitCopy 1080 if !copy { 1081 copy, err = m.confirm(&terraform.InputOpts{ 1082 Id: "backend-migrate-to-new", 1083 Query: fmt.Sprintf("Do you want to copy the state from %q?", c.Type), 1084 Description: strings.TrimSpace(fmt.Sprintf(inputBackendMigrateChange, c.Type, s.Backend.Type)), 1085 }) 1086 if err != nil { 1087 return nil, fmt.Errorf( 1088 "Error asking for state copy action: %s", err) 1089 } 1090 } 1091 1092 // If we are, then we need to initialize the old backend and 1093 // perform the copy. 1094 if copy { 1095 // Grab the existing backend 1096 oldB, err := m.backend_C_r_S_unchanged(c, sMgr) 1097 if err != nil { 1098 return nil, fmt.Errorf( 1099 "Error loading previously configured backend: %s", err) 1100 } 1101 1102 // Perform the migration 1103 err = m.backendMigrateState(&backendMigrateOpts{ 1104 OneType: s.Backend.Type, 1105 TwoType: c.Type, 1106 One: oldB, 1107 Two: b, 1108 }) 1109 if err != nil { 1110 return nil, err 1111 } 1112 } 1113 1114 if m.stateLock { 1115 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 1116 defer cancel() 1117 1118 // Lock the state if we can 1119 lockInfo := state.NewLockInfo() 1120 lockInfo.Operation = "backend from config" 1121 1122 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 1123 if err != nil { 1124 return nil, fmt.Errorf("Error locking state: %s", err) 1125 } 1126 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 1127 } 1128 1129 // Update the backend state 1130 s = sMgr.State() 1131 if s == nil { 1132 s = terraform.NewState() 1133 } 1134 s.Backend = &terraform.BackendState{ 1135 Type: c.Type, 1136 Config: c.RawConfig.Raw, 1137 Hash: c.Hash, 1138 } 1139 1140 if err := sMgr.WriteState(s); err != nil { 1141 return nil, fmt.Errorf(errBackendWriteSaved, err) 1142 } 1143 if err := sMgr.PersistState(); err != nil { 1144 return nil, fmt.Errorf(errBackendWriteSaved, err) 1145 } 1146 1147 if output { 1148 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1149 "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 1150 } 1151 1152 return b, nil 1153 } 1154 1155 // Initiailizing an unchanged saved backend 1156 func (m *Meta) backend_C_r_S_unchanged( 1157 c *config.Backend, sMgr state.State) (backend.Backend, error) { 1158 s := sMgr.State() 1159 1160 // it's possible for a backend to be unchanged, and the config itself to 1161 // have changed by moving a parameter from the config to `-backend-config` 1162 // In this case we only need to update the Hash. 1163 if c != nil && s.Backend.Hash != c.Hash { 1164 s.Backend.Hash = c.Hash 1165 if err := sMgr.WriteState(s); err != nil { 1166 return nil, fmt.Errorf(errBackendWriteSaved, err) 1167 } 1168 } 1169 1170 // Create the config. We do this from the backend state since this 1171 // has the complete configuration data whereas the config itself 1172 // may require input. 1173 rawC, err := config.NewRawConfig(s.Backend.Config) 1174 if err != nil { 1175 return nil, fmt.Errorf("Error configuring backend: %s", err) 1176 } 1177 config := terraform.NewResourceConfig(rawC) 1178 1179 // Get the backend 1180 f := backendinit.Backend(s.Backend.Type) 1181 if f == nil { 1182 return nil, fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type) 1183 } 1184 b := f() 1185 1186 // Configure 1187 if err := b.Configure(config); err != nil { 1188 return nil, fmt.Errorf(errBackendSavedConfig, s.Backend.Type, err) 1189 } 1190 1191 return b, nil 1192 } 1193 1194 // Initiailizing a changed saved backend with legacy remote state. 1195 func (m *Meta) backend_C_R_S_changed( 1196 c *config.Backend, sMgr state.State) (backend.Backend, error) { 1197 // Notify the user 1198 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1199 "[reset]%s\n\n", 1200 strings.TrimSpace(outputBackendSavedWithLegacyChanged)))) 1201 1202 // Reconfigure the backend first 1203 if _, err := m.backend_C_r_S_changed(c, sMgr, false); err != nil { 1204 return nil, err 1205 } 1206 1207 // Handle the case where we have all set but unchanged 1208 b, err := m.backend_C_R_S_unchanged(c, sMgr, false) 1209 if err != nil { 1210 return nil, err 1211 } 1212 1213 // Output success message 1214 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1215 "[reset][green]\n\n"+ 1216 strings.TrimSpace(successBackendReconfigureWithLegacy), c.Type))) 1217 1218 return b, nil 1219 } 1220 1221 // Initiailizing an unchanged saved backend with legacy remote state. 1222 func (m *Meta) backend_C_R_S_unchanged( 1223 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 1224 if output { 1225 // Notify the user 1226 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1227 "[reset]%s\n\n", 1228 strings.TrimSpace(outputBackendSavedWithLegacy)))) 1229 } 1230 1231 // Load the backend from the state 1232 s := sMgr.State() 1233 b, err := m.backendInitFromSaved(s.Backend) 1234 if err != nil { 1235 return nil, err 1236 } 1237 1238 // Ask if the user wants to move their legacy remote state 1239 copy := m.forceInitCopy 1240 if !copy { 1241 copy, err = m.confirm(&terraform.InputOpts{ 1242 Id: "backend-migrate-to-new", 1243 Query: fmt.Sprintf( 1244 "Do you want to copy the legacy remote state from %q?", 1245 s.Remote.Type), 1246 Description: strings.TrimSpace(inputBackendMigrateLegacy), 1247 }) 1248 if err != nil { 1249 return nil, fmt.Errorf( 1250 "Error asking for state copy action: %s", err) 1251 } 1252 } 1253 1254 // If the user wants a copy, copy! 1255 if copy { 1256 // Initialize the legacy backend 1257 oldB, err := m.backendInitFromLegacy(s.Remote) 1258 if err != nil { 1259 return nil, err 1260 } 1261 1262 // Perform the migration 1263 err = m.backendMigrateState(&backendMigrateOpts{ 1264 OneType: s.Remote.Type, 1265 TwoType: s.Backend.Type, 1266 One: oldB, 1267 Two: b, 1268 }) 1269 if err != nil { 1270 return nil, err 1271 } 1272 } 1273 1274 if m.stateLock { 1275 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 1276 defer cancel() 1277 1278 // Lock the state if we can 1279 lockInfo := state.NewLockInfo() 1280 lockInfo.Operation = "backend from config" 1281 1282 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 1283 if err != nil { 1284 return nil, fmt.Errorf("Error locking state: %s", err) 1285 } 1286 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 1287 } 1288 1289 // Unset the remote state 1290 s = sMgr.State() 1291 if s == nil { 1292 s = terraform.NewState() 1293 } 1294 s.Remote = nil 1295 1296 if err := sMgr.WriteState(s); err != nil { 1297 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 1298 } 1299 if err := sMgr.PersistState(); err != nil { 1300 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 1301 } 1302 1303 if output { 1304 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1305 "[reset][green]\n\n"+ 1306 strings.TrimSpace(successBackendLegacyUnset), s.Backend.Type))) 1307 } 1308 1309 return b, nil 1310 } 1311 1312 //------------------------------------------------------------------- 1313 // Reusable helper functions for backend management 1314 //------------------------------------------------------------------- 1315 1316 func (m *Meta) backendInitFromConfig(c *config.Backend) (backend.Backend, error) { 1317 // Create the config. 1318 config := terraform.NewResourceConfig(c.RawConfig) 1319 1320 // Get the backend 1321 f := backendinit.Backend(c.Type) 1322 if f == nil { 1323 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewUnknown), c.Type) 1324 } 1325 b := f() 1326 1327 // TODO: test 1328 // Ask for input if we have input enabled 1329 if m.Input() { 1330 var err error 1331 config, err = b.Input(m.UIInput(), config) 1332 if err != nil { 1333 return nil, fmt.Errorf( 1334 "Error asking for input to configure the backend %q: %s", 1335 c.Type, err) 1336 } 1337 } 1338 1339 // Validate 1340 warns, errs := b.Validate(config) 1341 for _, warning := range warns { 1342 // We just write warnings directly to the UI. This isn't great 1343 // since we're a bit deep here to be pushing stuff out into the 1344 // UI, but sufficient to let us print out deprecation warnings 1345 // and the like. 1346 m.Ui.Warn(warning) 1347 } 1348 if len(errs) > 0 { 1349 return nil, fmt.Errorf( 1350 "Error configuring the backend %q: %s", 1351 c.Type, multierror.Append(nil, errs...)) 1352 } 1353 1354 // Configure 1355 if err := b.Configure(config); err != nil { 1356 return nil, fmt.Errorf(errBackendNewConfig, c.Type, err) 1357 } 1358 1359 return b, nil 1360 } 1361 1362 func (m *Meta) backendInitFromLegacy(s *terraform.RemoteState) (backend.Backend, error) { 1363 // We need to convert the config to map[string]interface{} since that 1364 // is what the backends expect. 1365 var configMap map[string]interface{} 1366 if err := mapstructure.Decode(s.Config, &configMap); err != nil { 1367 return nil, fmt.Errorf("Error configuring remote state: %s", err) 1368 } 1369 1370 // Create the config 1371 rawC, err := config.NewRawConfig(configMap) 1372 if err != nil { 1373 return nil, fmt.Errorf("Error configuring remote state: %s", err) 1374 } 1375 config := terraform.NewResourceConfig(rawC) 1376 1377 // Get the backend 1378 f := backendinit.Backend(s.Type) 1379 if f == nil { 1380 return nil, fmt.Errorf(strings.TrimSpace(errBackendLegacyUnknown), s.Type) 1381 } 1382 b := f() 1383 1384 // Configure 1385 if err := b.Configure(config); err != nil { 1386 return nil, fmt.Errorf(errBackendLegacyConfig, err) 1387 } 1388 1389 return b, nil 1390 } 1391 1392 func (m *Meta) backendInitFromSaved(s *terraform.BackendState) (backend.Backend, error) { 1393 // Create the config. We do this from the backend state since this 1394 // has the complete configuration data whereas the config itself 1395 // may require input. 1396 rawC, err := config.NewRawConfig(s.Config) 1397 if err != nil { 1398 return nil, fmt.Errorf("Error configuring backend: %s", err) 1399 } 1400 config := terraform.NewResourceConfig(rawC) 1401 1402 // Get the backend 1403 f := backendinit.Backend(s.Type) 1404 if f == nil { 1405 return nil, fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Type) 1406 } 1407 b := f() 1408 1409 // Configure 1410 if err := b.Configure(config); err != nil { 1411 return nil, fmt.Errorf(errBackendSavedConfig, s.Type, err) 1412 } 1413 1414 return b, nil 1415 } 1416 1417 func (m *Meta) backendInitRequired(reason string) { 1418 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1419 "[reset]"+strings.TrimSpace(errBackendInit)+"\n", reason))) 1420 } 1421 1422 //------------------------------------------------------------------- 1423 // Output constants and initialization code 1424 //------------------------------------------------------------------- 1425 1426 // errBackendInitRequired is the final error message shown when reinit 1427 // is required for some reason. The error message includes the reason. 1428 var errBackendInitRequired = errors.New( 1429 "Initialization required. Please see the error message above.") 1430 1431 const errBackendLegacyConfig = ` 1432 One or more errors occurred while configuring the legacy remote state. 1433 If fixing these errors requires changing your remote state configuration, 1434 you must switch your configuration to the new remote backend configuration. 1435 You can learn more about remote backends at the URL below: 1436 1437 https://www.terraform.io/docs/backends/index.html 1438 1439 The error(s) configuring the legacy remote state: 1440 1441 %s 1442 ` 1443 1444 const errBackendLegacyUnknown = ` 1445 The legacy remote state type %q could not be found. 1446 1447 Terraform 0.9.0 shipped with backwards compatibility for all built-in 1448 legacy remote state types. This error may mean that you were using a 1449 custom Terraform build that perhaps supported a different type of 1450 remote state. 1451 1452 Please check with the creator of the remote state above and try again. 1453 ` 1454 1455 const errBackendLocalRead = ` 1456 Error reading local state: %s 1457 1458 Terraform is trying to read your local state to determine if there is 1459 state to migrate to your newly configured backend. Terraform can't continue 1460 without this check because that would risk losing state. Please resolve the 1461 error above and try again. 1462 ` 1463 1464 const errBackendMigrateLocalDelete = ` 1465 Error deleting local state after migration: %s 1466 1467 Your local state is deleted after successfully migrating it to the newly 1468 configured backend. As part of the deletion process, a backup is made at 1469 the standard backup path unless explicitly asked not to. To cleanly operate 1470 with a backend, we must delete the local state file. Please resolve the 1471 issue above and retry the command. 1472 ` 1473 1474 const errBackendMigrateNew = ` 1475 Error migrating local state to backend: %s 1476 1477 Your local state remains intact and unmodified. Please resolve the error 1478 above and try again. 1479 ` 1480 1481 const errBackendNewConfig = ` 1482 Error configuring the backend %q: %s 1483 1484 Please update the configuration in your Terraform files to fix this error 1485 then run this command again. 1486 ` 1487 1488 const errBackendNewRead = ` 1489 Error reading newly configured backend state: %s 1490 1491 Terraform is trying to read the state from your newly configured backend 1492 to determine the copy process for your existing state. Backends are expected 1493 to not error even if there is no state yet written. Please resolve the 1494 error above and try again. 1495 ` 1496 1497 const errBackendNewUnknown = ` 1498 The backend %q could not be found. 1499 1500 This is the backend specified in your Terraform configuration file. 1501 This error could be a simple typo in your configuration, but it can also 1502 be caused by using a Terraform version that doesn't support the specified 1503 backend type. Please check your configuration and your Terraform version. 1504 1505 If you'd like to run Terraform and store state locally, you can fix this 1506 error by removing the backend configuration from your configuration. 1507 ` 1508 1509 const errBackendRemoteRead = ` 1510 Error reading backend state: %s 1511 1512 Terraform is trying to read the state from your configured backend to 1513 determine if there is any migration steps necessary. Terraform can't continue 1514 without this check because that would risk losing state. Please resolve the 1515 error above and try again. 1516 ` 1517 1518 const errBackendSavedConfig = ` 1519 Error configuring the backend %q: %s 1520 1521 Please update the configuration in your Terraform files to fix this error. 1522 If you'd like to update the configuration interactively without storing 1523 the values in your configuration, run "terraform init". 1524 ` 1525 1526 const errBackendSavedUnsetConfig = ` 1527 Error configuring the existing backend %q: %s 1528 1529 Terraform must configure the existing backend in order to copy the state 1530 from the existing backend, as requested. Please resolve the error and try 1531 again. If you choose to not copy the existing state, Terraform will not 1532 configure the backend. If the configuration is invalid, please update your 1533 Terraform configuration with proper configuration for this backend first 1534 before unsetting the backend. 1535 ` 1536 1537 const errBackendSavedUnknown = ` 1538 The backend %q could not be found. 1539 1540 This is the backend that this Terraform environment is configured to use 1541 both in your configuration and saved locally as your last-used backend. 1542 If it isn't found, it could mean an alternate version of Terraform was 1543 used with this configuration. Please use the proper version of Terraform that 1544 contains support for this backend. 1545 1546 If you'd like to force remove this backend, you must update your configuration 1547 to not use the backend and run "terraform init" (or any other command) again. 1548 ` 1549 1550 const errBackendClearLegacy = ` 1551 Error clearing the legacy remote state configuration: %s 1552 1553 Terraform completed configuring your backend. It is now safe to remove 1554 the legacy remote state configuration, but an error occurred while trying 1555 to do so. Please look at the error above, resolve it, and try again. 1556 ` 1557 1558 const errBackendClearSaved = ` 1559 Error clearing the backend configuration: %s 1560 1561 Terraform removes the saved backend configuration when you're removing a 1562 configured backend. This must be done so future Terraform runs know to not 1563 use the backend configuration. Please look at the error above, resolve it, 1564 and try again. 1565 ` 1566 1567 const errBackendInit = ` 1568 [reset][bold][yellow]Backend reinitialization required. Please run "terraform init".[reset] 1569 [yellow]Reason: %s 1570 1571 The "backend" is the interface that Terraform uses to store state, 1572 perform operations, etc. If this message is showing up, it means that the 1573 Terraform configuration you're using is using a custom configuration for 1574 the Terraform backend. 1575 1576 Changes to backend configurations require reinitialization. This allows 1577 Terraform to setup the new configuration, copy existing state, etc. This is 1578 only done during "terraform init". Please run that command now then try again. 1579 1580 If the change reason above is incorrect, please verify your configuration 1581 hasn't changed and try again. At this point, no changes to your existing 1582 configuration or state have been made. 1583 ` 1584 1585 const errBackendWriteSaved = ` 1586 Error saving the backend configuration: %s 1587 1588 Terraform saves the complete backend configuration in a local file for 1589 configuring the backend on future operations. This cannot be disabled. Errors 1590 are usually due to simple file permission errors. Please look at the error 1591 above, resolve it, and try again. 1592 ` 1593 1594 const errBackendPlanBoth = ` 1595 The plan file contained both a legacy remote state and backend configuration. 1596 This is not allowed. Please recreate the plan file with the latest version of 1597 Terraform. 1598 ` 1599 1600 const errBackendPlanLineageDiff = ` 1601 The plan file contains a state with a differing lineage than the current 1602 state. By continuing, your current state would be overwritten by the state 1603 in the plan. Please either update the plan with the latest state or delete 1604 your current state and try again. 1605 1606 "Lineage" is a unique identifier generated only once on the creation of 1607 a new, empty state. If these values differ, it means they were created new 1608 at different times. Therefore, Terraform must assume that they're completely 1609 different states. 1610 1611 The most common cause of seeing this error is using a plan that was 1612 created against a different state. Perhaps the plan is very old and the 1613 state has since been recreated, or perhaps the plan was against a competely 1614 different infrastructure. 1615 ` 1616 1617 const errBackendPlanStateFlag = ` 1618 The -state and -state-out flags cannot be set with a plan that has a remote 1619 state. The plan itself contains the configuration for the remote backend to 1620 store state. The state will be written there for consistency. 1621 1622 If you wish to change this behavior, please create a plan from local state. 1623 You may use the state flags with plans from local state to affect where 1624 the final state is written. 1625 ` 1626 1627 const errBackendPlanOlder = ` 1628 This plan was created against an older state than is current. Please create 1629 a new plan file against the latest state and try again. 1630 1631 Terraform doesn't allow you to run plans that were created from older 1632 states since it doesn't properly represent the latest changes Terraform 1633 may have made, and can result in unsafe behavior. 1634 1635 Plan Serial: %[1]d 1636 Current Serial: %[2]d 1637 ` 1638 1639 const inputBackendMigrateChange = ` 1640 Would you like to copy the state from your prior backend %q to the 1641 newly configured %q backend? If you're reconfiguring the same backend, 1642 answering "yes" or "no" shouldn't make a difference. Please answer exactly 1643 "yes" or "no". 1644 ` 1645 1646 const inputBackendMigrateLegacy = ` 1647 Terraform can copy the existing state in your legacy remote state 1648 backend to your newly configured backend. Please answer "yes" or "no". 1649 ` 1650 1651 const inputBackendMigrateLegacyLocal = ` 1652 Terraform can copy the existing state in your legacy remote state 1653 backend to your local state. Please answer "yes" or "no". 1654 ` 1655 1656 const inputBackendMigrateLocal = ` 1657 Terraform has detected you're unconfiguring your previously set backend. 1658 Would you like to copy the state from %q to local state? Please answer 1659 "yes" or "no". If you answer "no", you will start with a blank local state. 1660 ` 1661 1662 const outputBackendConfigureWithLegacy = ` 1663 [reset][bold]New backend configuration detected with legacy remote state![reset] 1664 1665 Terraform has detected that you're attempting to configure a new backend. 1666 At the same time, legacy remote state configuration was found. Terraform will 1667 first configure the new backend, and then ask if you'd like to migrate 1668 your remote state to the new backend. 1669 ` 1670 1671 const outputBackendReconfigure = ` 1672 [reset][bold]Backend configuration changed![reset] 1673 1674 Terraform has detected that the configuration specified for the backend 1675 has changed. Terraform will now reconfigure for this backend. If you didn't 1676 intend to reconfigure your backend please undo any changes to the "backend" 1677 section in your Terraform configuration. 1678 ` 1679 1680 const outputBackendSavedWithLegacy = ` 1681 [reset][bold]Legacy remote state was detected![reset] 1682 1683 Terraform has detected you still have legacy remote state enabled while 1684 also having a backend configured. Terraform will now ask if you want to 1685 migrate your legacy remote state data to the configured backend. 1686 ` 1687 1688 const outputBackendSavedWithLegacyChanged = ` 1689 [reset][bold]Legacy remote state was detected while also changing your current backend!reset] 1690 1691 Terraform has detected that you have legacy remote state, a configured 1692 current backend, and you're attempting to reconfigure your backend. To handle 1693 all of these changes, Terraform will first reconfigure your backend. After 1694 this, Terraform will handle optionally copying your legacy remote state 1695 into the newly configured backend. 1696 ` 1697 1698 const outputBackendUnsetWithLegacy = ` 1699 [reset][bold]Detected a request to unset the backend with legacy remote state present![reset] 1700 1701 Terraform has detected that you're attempting to unset a previously configured 1702 backend (by not having the "backend" configuration set in your Terraform files). 1703 At the same time, legacy remote state was detected. To handle this complex 1704 scenario, Terraform will first unset your configured backend, and then 1705 ask you how to handle the legacy remote state. This will be multi-step 1706 process. 1707 ` 1708 1709 const successBackendLegacyUnset = ` 1710 Terraform has successfully migrated from legacy remote state to your 1711 configured backend (%q). 1712 ` 1713 1714 const successBackendReconfigureWithLegacy = ` 1715 Terraform has successfully reconfigured your backend and migrate 1716 from legacy remote state to the new backend. 1717 ` 1718 1719 const successBackendUnset = ` 1720 Successfully unset the backend %q. Terraform will now operate locally. 1721 ` 1722 1723 const successBackendSet = ` 1724 Successfully configured the backend %q! Terraform will automatically 1725 use this backend unless the backend configuration changes. 1726 ` 1727 1728 const warnBackendLegacy = ` 1729 Deprecation warning: This environment is configured to use legacy remote state. 1730 Remote state changed significantly in Terraform 0.9. Please update your remote 1731 state configuration to use the new 'backend' settings. For now, Terraform 1732 will continue to use your existing settings. Legacy remote state support 1733 will be removed in Terraform 0.11. 1734 1735 You can find a guide for upgrading here: 1736 1737 https://www.terraform.io/docs/backends/legacy-0-8.html 1738 `