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