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