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