github.com/posener/terraform@v0.11.0-beta1.0.20171103235147-645df36af025/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("[WARNING] 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 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 587 defer cancel() 588 589 // Lock the state if we can 590 lockInfo := state.NewLockInfo() 591 lockInfo.Operation = "backend from plan" 592 593 lockID, err := clistate.Lock(lockCtx, realMgr, lockInfo, m.Ui, m.Colorize()) 594 if err != nil { 595 return nil, fmt.Errorf("Error locking state: %s", err) 596 } 597 defer clistate.Unlock(realMgr, lockID, m.Ui, m.Colorize()) 598 } 599 600 if err := realMgr.RefreshState(); err != nil { 601 return nil, fmt.Errorf("Error reading state: %s", err) 602 } 603 real := realMgr.State() 604 if real != nil { 605 // If they're not the same lineage, don't allow this 606 if !real.SameLineage(planState) { 607 return nil, fmt.Errorf(strings.TrimSpace(errBackendPlanLineageDiff)) 608 } 609 610 // Compare ages 611 comp, err := real.CompareAges(planState) 612 if err != nil { 613 return nil, fmt.Errorf("Error comparing state ages for safety: %s", err) 614 } 615 switch comp { 616 case terraform.StateAgeEqual: 617 // State ages are equal, this is perfect 618 619 case terraform.StateAgeReceiverOlder: 620 // Real state is somehow older, this is okay. 621 622 case terraform.StateAgeReceiverNewer: 623 // If we have an older serial it is a problem but if we have a 624 // differing serial but are still identical, just let it through. 625 if real.Equal(planState) { 626 log.Printf( 627 "[WARN] command: state in plan has older serial, but Equal is true") 628 break 629 } 630 631 // The real state is newer, this is not allowed. 632 return nil, fmt.Errorf( 633 strings.TrimSpace(errBackendPlanOlder), 634 planState.Serial, real.Serial) 635 } 636 } 637 638 // Write the state 639 newState := opts.Plan.State.DeepCopy() 640 if newState != nil { 641 newState.Remote = nil 642 newState.Backend = nil 643 } 644 645 // realMgr locked above 646 if err := realMgr.WriteState(newState); err != nil { 647 return nil, fmt.Errorf("Error writing state: %s", err) 648 } 649 if err := realMgr.PersistState(); err != nil { 650 return nil, fmt.Errorf("Error writing state: %s", err) 651 } 652 653 return b, nil 654 } 655 656 //------------------------------------------------------------------- 657 // Backend Config Scenarios 658 // 659 // The functions below cover handling all the various scenarios that 660 // can exist when loading a backend. They are named in the format of 661 // "backend_C_R_S" where C, R, S may be upper or lowercase. Lowercase 662 // means it is false, uppercase means it is true. The full set of eight 663 // possible cases is handled. 664 // 665 // The fields are: 666 // 667 // * C - Backend configuration is set and changed in TF files 668 // * R - Legacy remote state is set 669 // * S - Backend configuration is set in the state 670 // 671 //------------------------------------------------------------------- 672 673 // Unconfiguring a backend (moving from backend => local). 674 func (m *Meta) backend_c_r_S( 675 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 676 s := sMgr.State() 677 678 // Get the backend type for output 679 backendType := s.Backend.Type 680 681 copy := m.forceInitCopy 682 if !copy { 683 var err error 684 // Confirm with the user that the copy should occur 685 copy, err = m.confirm(&terraform.InputOpts{ 686 Id: "backend-migrate-to-local", 687 Query: fmt.Sprintf("Do you want to copy the state from %q?", s.Backend.Type), 688 Description: fmt.Sprintf( 689 strings.TrimSpace(inputBackendMigrateLocal), s.Backend.Type), 690 }) 691 if err != nil { 692 return nil, fmt.Errorf( 693 "Error asking for state copy action: %s", err) 694 } 695 } 696 697 // If we're copying, perform the migration 698 if copy { 699 // Grab a purely local backend to get the local state if it exists 700 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 701 if err != nil { 702 return nil, fmt.Errorf(strings.TrimSpace(errBackendLocalRead), err) 703 } 704 705 // Initialize the configured backend 706 b, err := m.backend_C_r_S_unchanged(c, sMgr) 707 if err != nil { 708 return nil, fmt.Errorf( 709 strings.TrimSpace(errBackendSavedUnsetConfig), s.Backend.Type, err) 710 } 711 712 // Perform the migration 713 err = m.backendMigrateState(&backendMigrateOpts{ 714 OneType: s.Backend.Type, 715 TwoType: "local", 716 One: b, 717 Two: localB, 718 }) 719 if err != nil { 720 return nil, err 721 } 722 } 723 724 // Remove the stored metadata 725 s.Backend = nil 726 if err := sMgr.WriteState(s); err != nil { 727 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err) 728 } 729 if err := sMgr.PersistState(); err != nil { 730 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err) 731 } 732 733 if output { 734 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 735 "[reset][green]\n\n"+ 736 strings.TrimSpace(successBackendUnset), backendType))) 737 } 738 739 // Return no backend 740 return nil, nil 741 } 742 743 // Legacy remote state 744 func (m *Meta) backend_c_R_s( 745 c *config.Backend, sMgr state.State) (backend.Backend, error) { 746 s := sMgr.State() 747 748 // Warn the user 749 m.Ui.Warn(strings.TrimSpace(warnBackendLegacy) + "\n") 750 751 // We need to convert the config to map[string]interface{} since that 752 // is what the backends expect. 753 var configMap map[string]interface{} 754 if err := mapstructure.Decode(s.Remote.Config, &configMap); err != nil { 755 return nil, fmt.Errorf("Error configuring remote state: %s", err) 756 } 757 758 // Create the config 759 rawC, err := config.NewRawConfig(configMap) 760 if err != nil { 761 return nil, fmt.Errorf("Error configuring remote state: %s", err) 762 } 763 config := terraform.NewResourceConfig(rawC) 764 765 // Get the backend 766 f := backendinit.Backend(s.Remote.Type) 767 if f == nil { 768 return nil, fmt.Errorf(strings.TrimSpace(errBackendLegacyUnknown), s.Remote.Type) 769 } 770 b := f() 771 772 // Configure 773 if err := b.Configure(config); err != nil { 774 return nil, fmt.Errorf(errBackendLegacyConfig, err) 775 } 776 777 return b, nil 778 } 779 780 // Unsetting backend, saved backend, legacy remote state 781 func (m *Meta) backend_c_R_S( 782 c *config.Backend, sMgr state.State) (backend.Backend, error) { 783 // Notify the user 784 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 785 "[reset]%s\n\n", 786 strings.TrimSpace(outputBackendUnsetWithLegacy)))) 787 788 // Get the backend type for later 789 backendType := sMgr.State().Backend.Type 790 791 // First, perform the configured => local tranasition 792 if _, err := m.backend_c_r_S(c, sMgr, false); err != nil { 793 return nil, err 794 } 795 796 // Grab a purely local backend 797 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 798 if err != nil { 799 return nil, fmt.Errorf(errBackendLocalRead, err) 800 } 801 802 // Grab the state 803 s := sMgr.State() 804 805 // Ask the user if they want to migrate their existing remote state 806 copy := m.forceInitCopy 807 if !copy { 808 copy, err = m.confirm(&terraform.InputOpts{ 809 Id: "backend-migrate-to-new", 810 Query: fmt.Sprintf( 811 "Do you want to copy the legacy remote state from %q?", 812 s.Remote.Type), 813 Description: strings.TrimSpace(inputBackendMigrateLegacyLocal), 814 }) 815 if err != nil { 816 return nil, fmt.Errorf( 817 "Error asking for state copy action: %s", err) 818 } 819 } 820 821 // If the user wants a copy, copy! 822 if copy { 823 // Initialize the legacy backend 824 oldB, err := m.backendInitFromLegacy(s.Remote) 825 if err != nil { 826 return nil, err 827 } 828 829 // Perform the migration 830 err = m.backendMigrateState(&backendMigrateOpts{ 831 OneType: s.Remote.Type, 832 TwoType: "local", 833 One: oldB, 834 Two: localB, 835 }) 836 if err != nil { 837 return nil, err 838 } 839 } 840 841 // Unset the remote state 842 s = sMgr.State() 843 if s == nil { 844 s = terraform.NewState() 845 } 846 s.Remote = nil 847 if err := sMgr.WriteState(s); err != nil { 848 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 849 } 850 if err := sMgr.PersistState(); err != nil { 851 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 852 } 853 854 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 855 "[reset][green]\n\n"+ 856 strings.TrimSpace(successBackendUnset), backendType))) 857 858 return nil, nil 859 } 860 861 // Configuring a backend for the first time with legacy remote state. 862 func (m *Meta) backend_C_R_s( 863 c *config.Backend, sMgr state.State) (backend.Backend, error) { 864 // Notify the user 865 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 866 "[reset]%s\n\n", 867 strings.TrimSpace(outputBackendConfigureWithLegacy)))) 868 869 // First, configure the new backend 870 b, err := m.backendInitFromConfig(c) 871 if err != nil { 872 return nil, err 873 } 874 875 // Next, save the new configuration. This will not overwrite our 876 // legacy remote state. We'll handle that after. 877 s := sMgr.State() 878 if s == nil { 879 s = terraform.NewState() 880 } 881 s.Backend = &terraform.BackendState{ 882 Type: c.Type, 883 Config: c.RawConfig.Raw, 884 Hash: c.Hash, 885 } 886 if err := sMgr.WriteState(s); err != nil { 887 return nil, fmt.Errorf(errBackendWriteSaved, err) 888 } 889 if err := sMgr.PersistState(); err != nil { 890 return nil, fmt.Errorf(errBackendWriteSaved, err) 891 } 892 893 // I don't know how this is possible but if we don't have remote 894 // state config anymore somehow, just return the backend. This 895 // shouldn't be possible, though. 896 if s.Remote.Empty() { 897 return b, nil 898 } 899 900 // Finally, ask the user if they want to copy the state from 901 // their old remote state location. 902 copy := m.forceInitCopy 903 if !copy { 904 copy, err = m.confirm(&terraform.InputOpts{ 905 Id: "backend-migrate-to-new", 906 Query: fmt.Sprintf( 907 "Do you want to copy the legacy remote state from %q?", 908 s.Remote.Type), 909 Description: strings.TrimSpace(inputBackendMigrateLegacy), 910 }) 911 if err != nil { 912 return nil, fmt.Errorf( 913 "Error asking for state copy action: %s", err) 914 } 915 } 916 917 // If the user wants a copy, copy! 918 if copy { 919 // Initialize the legacy backend 920 oldB, err := m.backendInitFromLegacy(s.Remote) 921 if err != nil { 922 return nil, err 923 } 924 925 // Perform the migration 926 err = m.backendMigrateState(&backendMigrateOpts{ 927 OneType: s.Remote.Type, 928 TwoType: c.Type, 929 One: oldB, 930 Two: b, 931 }) 932 if err != nil { 933 return nil, err 934 } 935 } 936 937 // Unset the remote state 938 s = sMgr.State() 939 if s == nil { 940 s = terraform.NewState() 941 } 942 s.Remote = nil 943 if err := sMgr.WriteState(s); err != nil { 944 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 945 } 946 if err := sMgr.PersistState(); err != nil { 947 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 948 } 949 950 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 951 "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 952 953 return b, nil 954 } 955 956 // Configuring a backend for the first time. 957 func (m *Meta) backend_C_r_s( 958 c *config.Backend, sMgr state.State) (backend.Backend, error) { 959 // Get the backend 960 b, err := m.backendInitFromConfig(c) 961 if err != nil { 962 return nil, err 963 } 964 965 // Grab a purely local backend to get the local state if it exists 966 localB, err := m.Backend(&BackendOpts{ForceLocal: true}) 967 if err != nil { 968 return nil, fmt.Errorf(errBackendLocalRead, err) 969 } 970 971 env := m.Workspace() 972 973 localState, err := localB.State(env) 974 if err != nil { 975 return nil, fmt.Errorf(errBackendLocalRead, err) 976 } 977 if err := localState.RefreshState(); err != nil { 978 return nil, fmt.Errorf(errBackendLocalRead, err) 979 } 980 981 // If the local state is not empty, we need to potentially do a 982 // state migration to the new backend (with user permission), unless the 983 // destination is also "local" 984 if localS := localState.State(); !localS.Empty() { 985 // Perform the migration 986 err = m.backendMigrateState(&backendMigrateOpts{ 987 OneType: "local", 988 TwoType: c.Type, 989 One: localB, 990 Two: b, 991 }) 992 if err != nil { 993 return nil, err 994 } 995 996 // we usually remove the local state after migration to prevent 997 // confusion, but adding a default local backend block to the config 998 // can get us here too. Don't delete our state if the old and new paths 999 // are the same. 1000 erase := true 1001 if newLocalB, ok := b.(*backendlocal.Local); ok { 1002 if localB, ok := localB.(*backendlocal.Local); ok { 1003 if newLocalB.StatePath == localB.StatePath { 1004 erase = false 1005 } 1006 } 1007 } 1008 1009 if erase { 1010 // We always delete the local state, unless that was our new state too. 1011 if err := localState.WriteState(nil); err != nil { 1012 return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) 1013 } 1014 if err := localState.PersistState(); err != nil { 1015 return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) 1016 } 1017 } 1018 } 1019 1020 if m.stateLock { 1021 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 1022 defer cancel() 1023 1024 // Lock the state if we can 1025 lockInfo := state.NewLockInfo() 1026 lockInfo.Operation = "backend from config" 1027 1028 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 1029 if err != nil { 1030 return nil, fmt.Errorf("Error locking state: %s", err) 1031 } 1032 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 1033 } 1034 1035 // Store the metadata in our saved state location 1036 s := sMgr.State() 1037 if s == nil { 1038 s = terraform.NewState() 1039 } 1040 s.Backend = &terraform.BackendState{ 1041 Type: c.Type, 1042 Config: c.RawConfig.Raw, 1043 Hash: c.Hash, 1044 } 1045 1046 if err := sMgr.WriteState(s); err != nil { 1047 return nil, fmt.Errorf(errBackendWriteSaved, err) 1048 } 1049 if err := sMgr.PersistState(); err != nil { 1050 return nil, fmt.Errorf(errBackendWriteSaved, err) 1051 } 1052 1053 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1054 "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 1055 1056 // Return the backend 1057 return b, nil 1058 } 1059 1060 // Changing a previously saved backend. 1061 func (m *Meta) backend_C_r_S_changed( 1062 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 1063 if output { 1064 // Notify the user 1065 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1066 "[reset]%s\n\n", 1067 strings.TrimSpace(outputBackendReconfigure)))) 1068 } 1069 1070 // Get the old state 1071 s := sMgr.State() 1072 1073 // Get the backend 1074 b, err := m.backendInitFromConfig(c) 1075 if err != nil { 1076 return nil, fmt.Errorf( 1077 "Error initializing new backend: %s", err) 1078 } 1079 1080 // Check with the user if we want to migrate state 1081 copy := m.forceInitCopy 1082 if !copy { 1083 copy, err = m.confirm(&terraform.InputOpts{ 1084 Id: "backend-migrate-to-new", 1085 Query: fmt.Sprintf("Do you want to copy the state from %q?", s.Backend.Type), 1086 Description: strings.TrimSpace(fmt.Sprintf(inputBackendMigrateChange, s.Backend.Type, c.Type)), 1087 }) 1088 if err != nil { 1089 return nil, fmt.Errorf( 1090 "Error asking for state copy action: %s", err) 1091 } 1092 } 1093 1094 // If we are, then we need to initialize the old backend and 1095 // perform the copy. 1096 if copy { 1097 // Grab the existing backend 1098 oldB, err := m.backend_C_r_S_unchanged(c, sMgr) 1099 if err != nil { 1100 return nil, fmt.Errorf( 1101 "Error loading previously configured backend: %s", err) 1102 } 1103 1104 // Perform the migration 1105 err = m.backendMigrateState(&backendMigrateOpts{ 1106 OneType: s.Backend.Type, 1107 TwoType: c.Type, 1108 One: oldB, 1109 Two: b, 1110 }) 1111 if err != nil { 1112 return nil, err 1113 } 1114 } 1115 1116 if m.stateLock { 1117 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 1118 defer cancel() 1119 1120 // Lock the state if we can 1121 lockInfo := state.NewLockInfo() 1122 lockInfo.Operation = "backend from config" 1123 1124 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 1125 if err != nil { 1126 return nil, fmt.Errorf("Error locking state: %s", err) 1127 } 1128 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 1129 } 1130 1131 // Update the backend state 1132 s = sMgr.State() 1133 if s == nil { 1134 s = terraform.NewState() 1135 } 1136 s.Backend = &terraform.BackendState{ 1137 Type: c.Type, 1138 Config: c.RawConfig.Raw, 1139 Hash: c.Hash, 1140 } 1141 1142 if err := sMgr.WriteState(s); err != nil { 1143 return nil, fmt.Errorf(errBackendWriteSaved, err) 1144 } 1145 if err := sMgr.PersistState(); err != nil { 1146 return nil, fmt.Errorf(errBackendWriteSaved, err) 1147 } 1148 1149 if output { 1150 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1151 "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) 1152 } 1153 1154 return b, nil 1155 } 1156 1157 // Initiailizing an unchanged saved backend 1158 func (m *Meta) backend_C_r_S_unchanged( 1159 c *config.Backend, sMgr state.State) (backend.Backend, error) { 1160 s := sMgr.State() 1161 1162 // it's possible for a backend to be unchanged, and the config itself to 1163 // have changed by moving a parameter from the config to `-backend-config` 1164 // In this case we only need to update the Hash. 1165 if c != nil && s.Backend.Hash != c.Hash { 1166 s.Backend.Hash = c.Hash 1167 if err := sMgr.WriteState(s); err != nil { 1168 return nil, fmt.Errorf(errBackendWriteSaved, err) 1169 } 1170 } 1171 1172 // Create the config. We do this from the backend state since this 1173 // has the complete configuration data whereas the config itself 1174 // may require input. 1175 rawC, err := config.NewRawConfig(s.Backend.Config) 1176 if err != nil { 1177 return nil, fmt.Errorf("Error configuring backend: %s", err) 1178 } 1179 config := terraform.NewResourceConfig(rawC) 1180 1181 // Get the backend 1182 f := backendinit.Backend(s.Backend.Type) 1183 if f == nil { 1184 return nil, fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type) 1185 } 1186 b := f() 1187 1188 // Configure 1189 if err := b.Configure(config); err != nil { 1190 return nil, fmt.Errorf(errBackendSavedConfig, s.Backend.Type, err) 1191 } 1192 1193 return b, nil 1194 } 1195 1196 // Initiailizing a changed saved backend with legacy remote state. 1197 func (m *Meta) backend_C_R_S_changed( 1198 c *config.Backend, sMgr state.State) (backend.Backend, error) { 1199 // Notify the user 1200 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1201 "[reset]%s\n\n", 1202 strings.TrimSpace(outputBackendSavedWithLegacyChanged)))) 1203 1204 // Reconfigure the backend first 1205 if _, err := m.backend_C_r_S_changed(c, sMgr, false); err != nil { 1206 return nil, err 1207 } 1208 1209 // Handle the case where we have all set but unchanged 1210 b, err := m.backend_C_R_S_unchanged(c, sMgr, false) 1211 if err != nil { 1212 return nil, err 1213 } 1214 1215 // Output success message 1216 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1217 "[reset][green]\n\n"+ 1218 strings.TrimSpace(successBackendReconfigureWithLegacy), c.Type))) 1219 1220 return b, nil 1221 } 1222 1223 // Initiailizing an unchanged saved backend with legacy remote state. 1224 func (m *Meta) backend_C_R_S_unchanged( 1225 c *config.Backend, sMgr state.State, output bool) (backend.Backend, error) { 1226 if output { 1227 // Notify the user 1228 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1229 "[reset]%s\n\n", 1230 strings.TrimSpace(outputBackendSavedWithLegacy)))) 1231 } 1232 1233 // Load the backend from the state 1234 s := sMgr.State() 1235 b, err := m.backendInitFromSaved(s.Backend) 1236 if err != nil { 1237 return nil, err 1238 } 1239 1240 // Ask if the user wants to move their legacy remote state 1241 copy := m.forceInitCopy 1242 if !copy { 1243 copy, err = m.confirm(&terraform.InputOpts{ 1244 Id: "backend-migrate-to-new", 1245 Query: fmt.Sprintf( 1246 "Do you want to copy the legacy remote state from %q?", 1247 s.Remote.Type), 1248 Description: strings.TrimSpace(inputBackendMigrateLegacy), 1249 }) 1250 if err != nil { 1251 return nil, fmt.Errorf( 1252 "Error asking for state copy action: %s", err) 1253 } 1254 } 1255 1256 // If the user wants a copy, copy! 1257 if copy { 1258 // Initialize the legacy backend 1259 oldB, err := m.backendInitFromLegacy(s.Remote) 1260 if err != nil { 1261 return nil, err 1262 } 1263 1264 // Perform the migration 1265 err = m.backendMigrateState(&backendMigrateOpts{ 1266 OneType: s.Remote.Type, 1267 TwoType: s.Backend.Type, 1268 One: oldB, 1269 Two: b, 1270 }) 1271 if err != nil { 1272 return nil, err 1273 } 1274 } 1275 1276 if m.stateLock { 1277 lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout) 1278 defer cancel() 1279 1280 // Lock the state if we can 1281 lockInfo := state.NewLockInfo() 1282 lockInfo.Operation = "backend from config" 1283 1284 lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize()) 1285 if err != nil { 1286 return nil, fmt.Errorf("Error locking state: %s", err) 1287 } 1288 defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize()) 1289 } 1290 1291 // Unset the remote state 1292 s = sMgr.State() 1293 if s == nil { 1294 s = terraform.NewState() 1295 } 1296 s.Remote = nil 1297 1298 if err := sMgr.WriteState(s); err != nil { 1299 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 1300 } 1301 if err := sMgr.PersistState(); err != nil { 1302 return nil, fmt.Errorf(strings.TrimSpace(errBackendClearLegacy), err) 1303 } 1304 1305 if output { 1306 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1307 "[reset][green]\n\n"+ 1308 strings.TrimSpace(successBackendLegacyUnset), s.Backend.Type))) 1309 } 1310 1311 return b, nil 1312 } 1313 1314 //------------------------------------------------------------------- 1315 // Reusable helper functions for backend management 1316 //------------------------------------------------------------------- 1317 1318 func (m *Meta) backendInitFromConfig(c *config.Backend) (backend.Backend, error) { 1319 // Create the config. 1320 config := terraform.NewResourceConfig(c.RawConfig) 1321 1322 // Get the backend 1323 f := backendinit.Backend(c.Type) 1324 if f == nil { 1325 return nil, fmt.Errorf(strings.TrimSpace(errBackendNewUnknown), c.Type) 1326 } 1327 b := f() 1328 1329 // TODO: test 1330 // Ask for input if we have input enabled 1331 if m.Input() { 1332 var err error 1333 config, err = b.Input(m.UIInput(), config) 1334 if err != nil { 1335 return nil, fmt.Errorf( 1336 "Error asking for input to configure the backend %q: %s", 1337 c.Type, err) 1338 } 1339 } 1340 1341 // Validate 1342 warns, errs := b.Validate(config) 1343 for _, warning := range warns { 1344 // We just write warnings directly to the UI. This isn't great 1345 // since we're a bit deep here to be pushing stuff out into the 1346 // UI, but sufficient to let us print out deprecation warnings 1347 // and the like. 1348 m.Ui.Warn(warning) 1349 } 1350 if len(errs) > 0 { 1351 return nil, fmt.Errorf( 1352 "Error configuring the backend %q: %s", 1353 c.Type, multierror.Append(nil, errs...)) 1354 } 1355 1356 // Configure 1357 if err := b.Configure(config); err != nil { 1358 return nil, fmt.Errorf(errBackendNewConfig, c.Type, err) 1359 } 1360 1361 return b, nil 1362 } 1363 1364 func (m *Meta) backendInitFromLegacy(s *terraform.RemoteState) (backend.Backend, error) { 1365 // We need to convert the config to map[string]interface{} since that 1366 // is what the backends expect. 1367 var configMap map[string]interface{} 1368 if err := mapstructure.Decode(s.Config, &configMap); err != nil { 1369 return nil, fmt.Errorf("Error configuring remote state: %s", err) 1370 } 1371 1372 // Create the config 1373 rawC, err := config.NewRawConfig(configMap) 1374 if err != nil { 1375 return nil, fmt.Errorf("Error configuring remote state: %s", err) 1376 } 1377 config := terraform.NewResourceConfig(rawC) 1378 1379 // Get the backend 1380 f := backendinit.Backend(s.Type) 1381 if f == nil { 1382 return nil, fmt.Errorf(strings.TrimSpace(errBackendLegacyUnknown), s.Type) 1383 } 1384 b := f() 1385 1386 // Configure 1387 if err := b.Configure(config); err != nil { 1388 return nil, fmt.Errorf(errBackendLegacyConfig, err) 1389 } 1390 1391 return b, nil 1392 } 1393 1394 func (m *Meta) backendInitFromSaved(s *terraform.BackendState) (backend.Backend, error) { 1395 // Create the config. We do this from the backend state since this 1396 // has the complete configuration data whereas the config itself 1397 // may require input. 1398 rawC, err := config.NewRawConfig(s.Config) 1399 if err != nil { 1400 return nil, fmt.Errorf("Error configuring backend: %s", err) 1401 } 1402 config := terraform.NewResourceConfig(rawC) 1403 1404 // Get the backend 1405 f := backendinit.Backend(s.Type) 1406 if f == nil { 1407 return nil, fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Type) 1408 } 1409 b := f() 1410 1411 // Configure 1412 if err := b.Configure(config); err != nil { 1413 return nil, fmt.Errorf(errBackendSavedConfig, s.Type, err) 1414 } 1415 1416 return b, nil 1417 } 1418 1419 func (m *Meta) backendInitRequired(reason string) { 1420 m.Ui.Output(m.Colorize().Color(fmt.Sprintf( 1421 "[reset]"+strings.TrimSpace(errBackendInit)+"\n", reason))) 1422 } 1423 1424 //------------------------------------------------------------------- 1425 // Output constants and initialization code 1426 //------------------------------------------------------------------- 1427 1428 // errBackendInitRequired is the final error message shown when reinit 1429 // is required for some reason. The error message includes the reason. 1430 var errBackendInitRequired = errors.New( 1431 "Initialization required. Please see the error message above.") 1432 1433 const errBackendLegacyConfig = ` 1434 One or more errors occurred while configuring the legacy remote state. 1435 If fixing these errors requires changing your remote state configuration, 1436 you must switch your configuration to the new remote backend configuration. 1437 You can learn more about remote backends at the URL below: 1438 1439 https://www.terraform.io/docs/backends/index.html 1440 1441 The error(s) configuring the legacy remote state: 1442 1443 %s 1444 ` 1445 1446 const errBackendLegacyUnknown = ` 1447 The legacy remote state type %q could not be found. 1448 1449 Terraform 0.9.0 shipped with backwards compatibility for all built-in 1450 legacy remote state types. This error may mean that you were using a 1451 custom Terraform build that perhaps supported a different type of 1452 remote state. 1453 1454 Please check with the creator of the remote state above and try again. 1455 ` 1456 1457 const errBackendLocalRead = ` 1458 Error reading local state: %s 1459 1460 Terraform is trying to read your local state to determine if there is 1461 state to migrate to your newly configured backend. Terraform can't continue 1462 without this check because that would risk losing state. Please resolve the 1463 error above and try again. 1464 ` 1465 1466 const errBackendMigrateLocalDelete = ` 1467 Error deleting local state after migration: %s 1468 1469 Your local state is deleted after successfully migrating it to the newly 1470 configured backend. As part of the deletion process, a backup is made at 1471 the standard backup path unless explicitly asked not to. To cleanly operate 1472 with a backend, we must delete the local state file. Please resolve the 1473 issue above and retry the command. 1474 ` 1475 1476 const errBackendMigrateNew = ` 1477 Error migrating local state to backend: %s 1478 1479 Your local state remains intact and unmodified. Please resolve the error 1480 above and try again. 1481 ` 1482 1483 const errBackendNewConfig = ` 1484 Error configuring the backend %q: %s 1485 1486 Please update the configuration in your Terraform files to fix this error 1487 then run this command again. 1488 ` 1489 1490 const errBackendNewRead = ` 1491 Error reading newly configured backend state: %s 1492 1493 Terraform is trying to read the state from your newly configured backend 1494 to determine the copy process for your existing state. Backends are expected 1495 to not error even if there is no state yet written. Please resolve the 1496 error above and try again. 1497 ` 1498 1499 const errBackendNewUnknown = ` 1500 The backend %q could not be found. 1501 1502 This is the backend specified in your Terraform configuration file. 1503 This error could be a simple typo in your configuration, but it can also 1504 be caused by using a Terraform version that doesn't support the specified 1505 backend type. Please check your configuration and your Terraform version. 1506 1507 If you'd like to run Terraform and store state locally, you can fix this 1508 error by removing the backend configuration from your configuration. 1509 ` 1510 1511 const errBackendRemoteRead = ` 1512 Error reading backend state: %s 1513 1514 Terraform is trying to read the state from your configured backend to 1515 determine if there is any migration steps necessary. Terraform can't continue 1516 without this check because that would risk losing state. Please resolve the 1517 error above and try again. 1518 ` 1519 1520 const errBackendSavedConfig = ` 1521 Error configuring the backend %q: %s 1522 1523 Please update the configuration in your Terraform files to fix this error. 1524 If you'd like to update the configuration interactively without storing 1525 the values in your configuration, run "terraform init". 1526 ` 1527 1528 const errBackendSavedUnsetConfig = ` 1529 Error configuring the existing backend %q: %s 1530 1531 Terraform must configure the existing backend in order to copy the state 1532 from the existing backend, as requested. Please resolve the error and try 1533 again. If you choose to not copy the existing state, Terraform will not 1534 configure the backend. If the configuration is invalid, please update your 1535 Terraform configuration with proper configuration for this backend first 1536 before unsetting the backend. 1537 ` 1538 1539 const errBackendSavedUnknown = ` 1540 The backend %q could not be found. 1541 1542 This is the backend that this Terraform environment is configured to use 1543 both in your configuration and saved locally as your last-used backend. 1544 If it isn't found, it could mean an alternate version of Terraform was 1545 used with this configuration. Please use the proper version of Terraform that 1546 contains support for this backend. 1547 1548 If you'd like to force remove this backend, you must update your configuration 1549 to not use the backend and run "terraform init" (or any other command) again. 1550 ` 1551 1552 const errBackendClearLegacy = ` 1553 Error clearing the legacy remote state configuration: %s 1554 1555 Terraform completed configuring your backend. It is now safe to remove 1556 the legacy remote state configuration, but an error occurred while trying 1557 to do so. Please look at the error above, resolve it, and try again. 1558 ` 1559 1560 const errBackendClearSaved = ` 1561 Error clearing the backend configuration: %s 1562 1563 Terraform removes the saved backend configuration when you're removing a 1564 configured backend. This must be done so future Terraform runs know to not 1565 use the backend configuration. Please look at the error above, resolve it, 1566 and try again. 1567 ` 1568 1569 const errBackendInit = ` 1570 [reset][bold][yellow]Backend reinitialization required. Please run "terraform init".[reset] 1571 [yellow]Reason: %s 1572 1573 The "backend" is the interface that Terraform uses to store state, 1574 perform operations, etc. If this message is showing up, it means that the 1575 Terraform configuration you're using is using a custom configuration for 1576 the Terraform backend. 1577 1578 Changes to backend configurations require reinitialization. This allows 1579 Terraform to setup the new configuration, copy existing state, etc. This is 1580 only done during "terraform init". Please run that command now then try again. 1581 1582 If the change reason above is incorrect, please verify your configuration 1583 hasn't changed and try again. At this point, no changes to your existing 1584 configuration or state have been made. 1585 ` 1586 1587 const errBackendWriteSaved = ` 1588 Error saving the backend configuration: %s 1589 1590 Terraform saves the complete backend configuration in a local file for 1591 configuring the backend on future operations. This cannot be disabled. Errors 1592 are usually due to simple file permission errors. Please look at the error 1593 above, resolve it, and try again. 1594 ` 1595 1596 const errBackendPlanBoth = ` 1597 The plan file contained both a legacy remote state and backend configuration. 1598 This is not allowed. Please recreate the plan file with the latest version of 1599 Terraform. 1600 ` 1601 1602 const errBackendPlanLineageDiff = ` 1603 The plan file contains a state with a differing lineage than the current 1604 state. By continuing, your current state would be overwritten by the state 1605 in the plan. Please either update the plan with the latest state or delete 1606 your current state and try again. 1607 1608 "Lineage" is a unique identifier generated only once on the creation of 1609 a new, empty state. If these values differ, it means they were created new 1610 at different times. Therefore, Terraform must assume that they're completely 1611 different states. 1612 1613 The most common cause of seeing this error is using a plan that was 1614 created against a different state. Perhaps the plan is very old and the 1615 state has since been recreated, or perhaps the plan was against a competely 1616 different infrastructure. 1617 ` 1618 1619 const errBackendPlanStateFlag = ` 1620 The -state and -state-out flags cannot be set with a plan that has a remote 1621 state. The plan itself contains the configuration for the remote backend to 1622 store state. The state will be written there for consistency. 1623 1624 If you wish to change this behavior, please create a plan from local state. 1625 You may use the state flags with plans from local state to affect where 1626 the final state is written. 1627 ` 1628 1629 const errBackendPlanOlder = ` 1630 This plan was created against an older state than is current. Please create 1631 a new plan file against the latest state and try again. 1632 1633 Terraform doesn't allow you to run plans that were created from older 1634 states since it doesn't properly represent the latest changes Terraform 1635 may have made, and can result in unsafe behavior. 1636 1637 Plan Serial: %[1]d 1638 Current Serial: %[2]d 1639 ` 1640 1641 const inputBackendMigrateChange = ` 1642 Would you like to copy the state from your prior backend %q to the 1643 newly configured %q backend? If you're reconfiguring the same backend, 1644 answering "yes" or "no" shouldn't make a difference. Please answer exactly 1645 "yes" or "no". 1646 ` 1647 1648 const inputBackendMigrateLegacy = ` 1649 Terraform can copy the existing state in your legacy remote state 1650 backend to your newly configured backend. Please answer "yes" or "no". 1651 ` 1652 1653 const inputBackendMigrateLegacyLocal = ` 1654 Terraform can copy the existing state in your legacy remote state 1655 backend to your local state. Please answer "yes" or "no". 1656 ` 1657 1658 const inputBackendMigrateLocal = ` 1659 Terraform has detected you're unconfiguring your previously set backend. 1660 Would you like to copy the state from %q to local state? Please answer 1661 "yes" or "no". If you answer "no", you will start with a blank local state. 1662 ` 1663 1664 const outputBackendConfigureWithLegacy = ` 1665 [reset][bold]New backend configuration detected with legacy remote state![reset] 1666 1667 Terraform has detected that you're attempting to configure a new backend. 1668 At the same time, legacy remote state configuration was found. Terraform will 1669 first configure the new backend, and then ask if you'd like to migrate 1670 your remote state to the new backend. 1671 ` 1672 1673 const outputBackendReconfigure = ` 1674 [reset][bold]Backend configuration changed![reset] 1675 1676 Terraform has detected that the configuration specified for the backend 1677 has changed. Terraform will now reconfigure for this backend. If you didn't 1678 intend to reconfigure your backend please undo any changes to the "backend" 1679 section in your Terraform configuration. 1680 ` 1681 1682 const outputBackendSavedWithLegacy = ` 1683 [reset][bold]Legacy remote state was detected![reset] 1684 1685 Terraform has detected you still have legacy remote state enabled while 1686 also having a backend configured. Terraform will now ask if you want to 1687 migrate your legacy remote state data to the configured backend. 1688 ` 1689 1690 const outputBackendSavedWithLegacyChanged = ` 1691 [reset][bold]Legacy remote state was detected while also changing your current backend!reset] 1692 1693 Terraform has detected that you have legacy remote state, a configured 1694 current backend, and you're attempting to reconfigure your backend. To handle 1695 all of these changes, Terraform will first reconfigure your backend. After 1696 this, Terraform will handle optionally copying your legacy remote state 1697 into the newly configured backend. 1698 ` 1699 1700 const outputBackendUnsetWithLegacy = ` 1701 [reset][bold]Detected a request to unset the backend with legacy remote state present![reset] 1702 1703 Terraform has detected that you're attempting to unset a previously configured 1704 backend (by not having the "backend" configuration set in your Terraform files). 1705 At the same time, legacy remote state was detected. To handle this complex 1706 scenario, Terraform will first unset your configured backend, and then 1707 ask you how to handle the legacy remote state. This will be multi-step 1708 process. 1709 ` 1710 1711 const successBackendLegacyUnset = ` 1712 Terraform has successfully migrated from legacy remote state to your 1713 configured backend (%q). 1714 ` 1715 1716 const successBackendReconfigureWithLegacy = ` 1717 Terraform has successfully reconfigured your backend and migrate 1718 from legacy remote state to the new backend. 1719 ` 1720 1721 const successBackendUnset = ` 1722 Successfully unset the backend %q. Terraform will now operate locally. 1723 ` 1724 1725 const successBackendSet = ` 1726 Successfully configured the backend %q! Terraform will automatically 1727 use this backend unless the backend configuration changes. 1728 ` 1729 1730 const warnBackendLegacy = ` 1731 Deprecation warning: This environment is configured to use legacy remote state. 1732 Remote state changed significantly in Terraform 0.9. Please update your remote 1733 state configuration to use the new 'backend' settings. For now, Terraform 1734 will continue to use your existing settings. Legacy remote state support 1735 will be removed in Terraform 0.11. 1736 1737 You can find a guide for upgrading here: 1738 1739 https://www.terraform.io/docs/backends/legacy-0-8.html 1740 `