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