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