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