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