github.com/vic3lord/terraform@v0.8.0-rc1.0.20170626102919-16c6dd2cb372/command/meta_backend.go (about)

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