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