github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/command/meta_backend.go (about)

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