github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/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  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"log"
    12  	"path/filepath"
    13  	"strconv"
    14  	"strings"
    15  
    16  	"github.com/hashicorp/errwrap"
    17  	"github.com/hashicorp/hcl/v2"
    18  	"github.com/hashicorp/hcl/v2/hcldec"
    19  	"github.com/hashicorp/terraform/backend"
    20  	"github.com/hashicorp/terraform/command/clistate"
    21  	"github.com/hashicorp/terraform/configs"
    22  	"github.com/hashicorp/terraform/plans"
    23  	"github.com/hashicorp/terraform/state"
    24  	"github.com/hashicorp/terraform/terraform"
    25  	"github.com/hashicorp/terraform/tfdiags"
    26  	"github.com/zclconf/go-cty/cty"
    27  	ctyjson "github.com/zclconf/go-cty/cty/json"
    28  
    29  	backendInit "github.com/hashicorp/terraform/backend/init"
    30  	backendLocal "github.com/hashicorp/terraform/backend/local"
    31  )
    32  
    33  // BackendOpts are the options used to initialize a backend.Backend.
    34  type BackendOpts struct {
    35  	// Config is a representation of the backend configuration block given in
    36  	// the root module, or nil if no such block is present.
    37  	Config *configs.Backend
    38  
    39  	// ConfigOverride is an hcl.Body that, if non-nil, will be used with
    40  	// configs.MergeBodies to override the type-specific backend configuration
    41  	// arguments in Config.
    42  	ConfigOverride hcl.Body
    43  
    44  	// Init should be set to true if initialization is allowed. If this is
    45  	// false, then any configuration that requires configuration will show
    46  	// an error asking the user to reinitialize.
    47  	Init bool
    48  
    49  	// ForceLocal will force a purely local backend, including state.
    50  	// You probably don't want to set this.
    51  	ForceLocal bool
    52  }
    53  
    54  // Backend initializes and returns the backend for this CLI session.
    55  //
    56  // The backend is used to perform the actual Terraform operations. This
    57  // abstraction enables easily sliding in new Terraform behavior such as
    58  // remote state storage, remote operations, etc. while allowing the CLI
    59  // to remain mostly identical.
    60  //
    61  // This will initialize a new backend for each call, which can carry some
    62  // overhead with it. Please reuse the returned value for optimal behavior.
    63  //
    64  // Only one backend should be used per Meta. This function is stateful
    65  // and is unsafe to create multiple backends used at once. This function
    66  // can be called multiple times with each backend being "live" (usable)
    67  // one at a time.
    68  //
    69  // A side-effect of this method is the population of m.backendState, recording
    70  // the final resolved backend configuration after dealing with overrides from
    71  // the "terraform init" command line, etc.
    72  func (m *Meta) Backend(opts *BackendOpts) (backend.Enhanced, tfdiags.Diagnostics) {
    73  	var diags tfdiags.Diagnostics
    74  
    75  	// If no opts are set, then initialize
    76  	if opts == nil {
    77  		opts = &BackendOpts{}
    78  	}
    79  
    80  	// Initialize a backend from the config unless we're forcing a purely
    81  	// local operation.
    82  	var b backend.Backend
    83  	if !opts.ForceLocal {
    84  		var backendDiags tfdiags.Diagnostics
    85  		b, backendDiags = m.backendFromConfig(opts)
    86  		diags = diags.Append(backendDiags)
    87  
    88  		if opts.Init && b != nil && !diags.HasErrors() {
    89  			// Its possible that the currently selected workspace doesn't exist, so
    90  			// we call selectWorkspace to ensure an existing workspace is selected.
    91  			if err := m.selectWorkspace(b); err != nil {
    92  				diags = diags.Append(err)
    93  			}
    94  		}
    95  
    96  		if diags.HasErrors() {
    97  			return nil, diags
    98  		}
    99  
   100  		log.Printf("[TRACE] Meta.Backend: instantiated backend of type %T", b)
   101  	}
   102  
   103  	// Setup the CLI opts we pass into backends that support it.
   104  	cliOpts := m.backendCLIOpts()
   105  	cliOpts.Validation = true
   106  
   107  	// If the backend supports CLI initialization, do it.
   108  	if cli, ok := b.(backend.CLI); ok {
   109  		if err := cli.CLIInit(cliOpts); err != nil {
   110  			diags = diags.Append(fmt.Errorf(
   111  				"Error initializing backend %T: %s\n\n"+
   112  					"This is a bug; please report it to the backend developer",
   113  				b, err,
   114  			))
   115  			return nil, diags
   116  		}
   117  	}
   118  
   119  	// If the result of loading the backend is an enhanced backend,
   120  	// then return that as-is. This works even if b == nil (it will be !ok).
   121  	if enhanced, ok := b.(backend.Enhanced); ok {
   122  		log.Printf("[TRACE] Meta.Backend: backend %T supports operations", b)
   123  		return enhanced, nil
   124  	}
   125  
   126  	// We either have a non-enhanced backend or no backend configured at
   127  	// all. In either case, we use local as our enhanced backend and the
   128  	// non-enhanced (if any) as the state backend.
   129  
   130  	if !opts.ForceLocal {
   131  		log.Printf("[TRACE] Meta.Backend: backend %T does not support operations, so wrapping it in a local backend", b)
   132  	}
   133  
   134  	// Build the local backend
   135  	local := backendLocal.NewWithBackend(b)
   136  	if err := local.CLIInit(cliOpts); err != nil {
   137  		// Local backend isn't allowed to fail. It would be a bug.
   138  		panic(err)
   139  	}
   140  
   141  	// If we got here from backendFromConfig returning nil then m.backendState
   142  	// won't be set, since that codepath considers that to be no backend at all,
   143  	// but our caller considers that to be the local backend with no config
   144  	// and so we'll synthesize a backend state so other code doesn't need to
   145  	// care about this special case.
   146  	//
   147  	// FIXME: We should refactor this so that we more directly and explicitly
   148  	// treat the local backend as the default, including in the UI shown to
   149  	// the user, since the local backend should only be used when learning or
   150  	// in exceptional cases and so it's better to help the user learn that
   151  	// by introducing it as a concept.
   152  	if m.backendState == nil {
   153  		// NOTE: This synthetic object is intentionally _not_ retained in the
   154  		// on-disk record of the backend configuration, which was already dealt
   155  		// with inside backendFromConfig, because we still need that codepath
   156  		// to be able to recognize the lack of a config as distinct from
   157  		// explicitly setting local until we do some more refactoring here.
   158  		m.backendState = &terraform.BackendState{
   159  			Type:      "local",
   160  			ConfigRaw: json.RawMessage("{}"),
   161  		}
   162  	}
   163  
   164  	return local, nil
   165  }
   166  
   167  // selectWorkspace gets a list of existing workspaces and then checks
   168  // if the currently selected workspace is valid. If not, it will ask
   169  // the user to select a workspace from the list.
   170  func (m *Meta) selectWorkspace(b backend.Backend) error {
   171  	workspaces, err := b.Workspaces()
   172  	if err == backend.ErrWorkspacesNotSupported {
   173  		return nil
   174  	}
   175  	if err != nil {
   176  		return fmt.Errorf("Failed to get existing workspaces: %s", err)
   177  	}
   178  	if len(workspaces) == 0 {
   179  		return fmt.Errorf(strings.TrimSpace(errBackendNoExistingWorkspaces))
   180  	}
   181  
   182  	// Get the currently selected workspace.
   183  	workspace := m.Workspace()
   184  
   185  	// Check if any of the existing workspaces matches the selected
   186  	// workspace and create a numbered list of existing workspaces.
   187  	var list strings.Builder
   188  	for i, w := range workspaces {
   189  		if w == workspace {
   190  			return nil
   191  		}
   192  		fmt.Fprintf(&list, "%d. %s\n", i+1, w)
   193  	}
   194  
   195  	// If the selected workspace doesn't exist, ask the user to select
   196  	// a workspace from the list of existing workspaces.
   197  	v, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
   198  		Id: "select-workspace",
   199  		Query: fmt.Sprintf(
   200  			"\n[reset][bold][yellow]The currently selected workspace (%s) does not exist.[reset]",
   201  			workspace),
   202  		Description: fmt.Sprintf(
   203  			strings.TrimSpace(inputBackendSelectWorkspace), list.String()),
   204  	})
   205  	if err != nil {
   206  		return fmt.Errorf("Failed to select workspace: %s", err)
   207  	}
   208  
   209  	idx, err := strconv.Atoi(v)
   210  	if err != nil || (idx < 1 || idx > len(workspaces)) {
   211  		return fmt.Errorf("Failed to select workspace: input not a valid number")
   212  	}
   213  
   214  	return m.SetWorkspace(workspaces[idx-1])
   215  }
   216  
   217  // BackendForPlan is similar to Backend, but uses backend settings that were
   218  // stored in a plan.
   219  //
   220  // The current workspace name is also stored as part of the plan, and so this
   221  // method will check that it matches the currently-selected workspace name
   222  // and produce error diagnostics if not.
   223  func (m *Meta) BackendForPlan(settings plans.Backend) (backend.Enhanced, tfdiags.Diagnostics) {
   224  	var diags tfdiags.Diagnostics
   225  
   226  	f := backendInit.Backend(settings.Type)
   227  	if f == nil {
   228  		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), settings.Type))
   229  		return nil, diags
   230  	}
   231  	b := f()
   232  	log.Printf("[TRACE] Meta.BackendForPlan: instantiated backend of type %T", b)
   233  
   234  	schema := b.ConfigSchema()
   235  	configVal, err := settings.Config.Decode(schema.ImpliedType())
   236  	if err != nil {
   237  		diags = diags.Append(errwrap.Wrapf("saved backend configuration is invalid: {{err}}", err))
   238  		return nil, diags
   239  	}
   240  
   241  	newVal, validateDiags := b.PrepareConfig(configVal)
   242  	diags = diags.Append(validateDiags)
   243  	if validateDiags.HasErrors() {
   244  		return nil, diags
   245  	}
   246  
   247  	configureDiags := b.Configure(newVal)
   248  	diags = diags.Append(configureDiags)
   249  
   250  	// If the backend supports CLI initialization, do it.
   251  	if cli, ok := b.(backend.CLI); ok {
   252  		cliOpts := m.backendCLIOpts()
   253  		if err := cli.CLIInit(cliOpts); err != nil {
   254  			diags = diags.Append(fmt.Errorf(
   255  				"Error initializing backend %T: %s\n\n"+
   256  					"This is a bug; please report it to the backend developer",
   257  				b, err,
   258  			))
   259  			return nil, diags
   260  		}
   261  	}
   262  
   263  	// If the result of loading the backend is an enhanced backend,
   264  	// then return that as-is. This works even if b == nil (it will be !ok).
   265  	if enhanced, ok := b.(backend.Enhanced); ok {
   266  		log.Printf("[TRACE] Meta.BackendForPlan: backend %T supports operations", b)
   267  		return enhanced, nil
   268  	}
   269  
   270  	// Otherwise, we'll wrap our state-only remote backend in the local backend
   271  	// to cause any operations to be run locally.
   272  	log.Printf("[TRACE] Meta.Backend: backend %T does not support operations, so wrapping it in a local backend", b)
   273  	cliOpts := m.backendCLIOpts()
   274  	cliOpts.Validation = false // don't validate here in case config contains file(...) calls where the file doesn't exist
   275  	local := backendLocal.NewWithBackend(b)
   276  	if err := local.CLIInit(cliOpts); err != nil {
   277  		// Local backend should never fail, so this is always a bug.
   278  		panic(err)
   279  	}
   280  
   281  	return local, diags
   282  }
   283  
   284  // backendCLIOpts returns a backend.CLIOpts object that should be passed to
   285  // a backend that supports local CLI operations.
   286  func (m *Meta) backendCLIOpts() *backend.CLIOpts {
   287  	return &backend.CLIOpts{
   288  		CLI:                 m.Ui,
   289  		CLIColor:            m.Colorize(),
   290  		ShowDiagnostics:     m.showDiagnostics,
   291  		StatePath:           m.statePath,
   292  		StateOutPath:        m.stateOutPath,
   293  		StateBackupPath:     m.backupPath,
   294  		ContextOpts:         m.contextOpts(),
   295  		Input:               m.Input(),
   296  		RunningInAutomation: m.RunningInAutomation,
   297  	}
   298  }
   299  
   300  // IsLocalBackend returns true if the backend is a local backend. We use this
   301  // for some checks that require a remote backend.
   302  func (m *Meta) IsLocalBackend(b backend.Backend) bool {
   303  	// Is it a local backend?
   304  	bLocal, ok := b.(*backendLocal.Local)
   305  
   306  	// If it is, does it not have an alternate state backend?
   307  	if ok {
   308  		ok = bLocal.Backend == nil
   309  	}
   310  
   311  	return ok
   312  }
   313  
   314  // Operation initializes a new backend.Operation struct.
   315  //
   316  // This prepares the operation. After calling this, the caller is expected
   317  // to modify fields of the operation such as Sequence to specify what will
   318  // be called.
   319  func (m *Meta) Operation(b backend.Backend) *backend.Operation {
   320  	schema := b.ConfigSchema()
   321  	workspace := m.Workspace()
   322  	planOutBackend, err := m.backendState.ForPlan(schema, workspace)
   323  	if err != nil {
   324  		// Always indicates an implementation error in practice, because
   325  		// errors here indicate invalid encoding of the backend configuration
   326  		// in memory, and we should always have validated that by the time
   327  		// we get here.
   328  		panic(fmt.Sprintf("failed to encode backend configuration for plan: %s", err))
   329  	}
   330  
   331  	return &backend.Operation{
   332  		PlanOutBackend:   planOutBackend,
   333  		Parallelism:      m.parallelism,
   334  		Targets:          m.targets,
   335  		UIIn:             m.UIInput(),
   336  		UIOut:            m.Ui,
   337  		Workspace:        workspace,
   338  		LockState:        m.stateLock,
   339  		StateLockTimeout: m.stateLockTimeout,
   340  	}
   341  }
   342  
   343  // backendConfig returns the local configuration for the backend
   344  func (m *Meta) backendConfig(opts *BackendOpts) (*configs.Backend, int, tfdiags.Diagnostics) {
   345  	var diags tfdiags.Diagnostics
   346  
   347  	if opts.Config == nil {
   348  		// check if the config was missing, or just not required
   349  		conf, moreDiags := m.loadBackendConfig(".")
   350  		diags = diags.Append(moreDiags)
   351  		if moreDiags.HasErrors() {
   352  			return nil, 0, diags
   353  		}
   354  
   355  		if conf == nil {
   356  			log.Println("[TRACE] Meta.Backend: no config given or present on disk, so returning nil config")
   357  			return nil, 0, nil
   358  		}
   359  
   360  		log.Printf("[TRACE] Meta.Backend: BackendOpts.Config not set, so using settings loaded from %s", conf.DeclRange)
   361  		opts.Config = conf
   362  	}
   363  
   364  	c := opts.Config
   365  
   366  	if c == nil {
   367  		log.Println("[TRACE] Meta.Backend: no explicit backend config, so returning nil config")
   368  		return nil, 0, nil
   369  	}
   370  
   371  	bf := backendInit.Backend(c.Type)
   372  	if bf == nil {
   373  		diags = diags.Append(&hcl.Diagnostic{
   374  			Severity: hcl.DiagError,
   375  			Summary:  "Invalid backend type",
   376  			Detail:   fmt.Sprintf("There is no backend type named %q.", c.Type),
   377  			Subject:  &c.TypeRange,
   378  		})
   379  		return nil, 0, diags
   380  	}
   381  	b := bf()
   382  
   383  	configSchema := b.ConfigSchema()
   384  	configBody := c.Config
   385  	configHash := c.Hash(configSchema)
   386  
   387  	// If we have an override configuration body then we must apply it now.
   388  	if opts.ConfigOverride != nil {
   389  		log.Println("[TRACE] Meta.Backend: merging -backend-config=... CLI overrides into backend configuration")
   390  		configBody = configs.MergeBodies(configBody, opts.ConfigOverride)
   391  	}
   392  
   393  	log.Printf("[TRACE] Meta.Backend: built configuration for %q backend with hash value %d", c.Type, configHash)
   394  
   395  	// We'll shallow-copy configs.Backend here so that we can replace the
   396  	// body without affecting others that hold this reference.
   397  	configCopy := *c
   398  	configCopy.Config = configBody
   399  	return &configCopy, configHash, diags
   400  }
   401  
   402  // backendFromConfig returns the initialized (not configured) backend
   403  // directly from the config/state..
   404  //
   405  // This function handles various edge cases around backend config loading. For
   406  // example: new config changes, backend type changes, etc.
   407  //
   408  // As of the 0.12 release it can no longer migrate from legacy remote state
   409  // to backends, and will instead instruct users to use 0.11 or earlier as
   410  // a stepping-stone to do that migration.
   411  //
   412  // This function may query the user for input unless input is disabled, in
   413  // which case this function will error.
   414  func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Diagnostics) {
   415  	// Get the local backend configuration.
   416  	c, cHash, diags := m.backendConfig(opts)
   417  	if diags.HasErrors() {
   418  		return nil, diags
   419  	}
   420  
   421  	// ------------------------------------------------------------------------
   422  	// For historical reasons, current backend configuration for a working
   423  	// directory is kept in a *state-like* file, using the legacy state
   424  	// structures in the Terraform package. It is not actually a Terraform
   425  	// state, and so only the "backend" portion of it is actually used.
   426  	//
   427  	// The remainder of this code often confusingly refers to this as a "state",
   428  	// so it's unfortunately important to remember that this is not actually
   429  	// what we _usually_ think of as "state", and is instead a local working
   430  	// directory "backend configuration state" that is never persisted anywhere.
   431  	//
   432  	// Since the "real" state has since moved on to be represented by
   433  	// states.State, we can recognize the special meaning of state that applies
   434  	// to this function and its callees by their continued use of the
   435  	// otherwise-obsolete terraform.State.
   436  	// ------------------------------------------------------------------------
   437  
   438  	// Get the path to where we store a local cache of backend configuration
   439  	// if we're using a remote backend. This may not yet exist which means
   440  	// we haven't used a non-local backend before. That is okay.
   441  	statePath := filepath.Join(m.DataDir(), DefaultStateFilename)
   442  	sMgr := &state.LocalState{Path: statePath}
   443  	if err := sMgr.RefreshState(); err != nil {
   444  		diags = diags.Append(fmt.Errorf("Failed to load state: %s", err))
   445  		return nil, diags
   446  	}
   447  
   448  	// Load the state, it must be non-nil for the tests below but can be empty
   449  	s := sMgr.State()
   450  	if s == nil {
   451  		log.Printf("[TRACE] Meta.Backend: backend has not previously been initialized in this working directory")
   452  		s = terraform.NewState()
   453  	} else if s.Backend != nil {
   454  		log.Printf("[TRACE] Meta.Backend: working directory was previously initialized for %q backend", s.Backend.Type)
   455  	} else {
   456  		log.Printf("[TRACE] Meta.Backend: working directory was previously initialized but has no backend (is using legacy remote state?)")
   457  	}
   458  
   459  	// if we want to force reconfiguration of the backend, we set the backend
   460  	// state to nil on this copy. This will direct us through the correct
   461  	// configuration path in the switch statement below.
   462  	if m.reconfigure {
   463  		s.Backend = nil
   464  	}
   465  
   466  	// Upon return, we want to set the state we're using in-memory so that
   467  	// we can access it for commands.
   468  	m.backendState = nil
   469  	defer func() {
   470  		if s := sMgr.State(); s != nil && !s.Backend.Empty() {
   471  			m.backendState = s.Backend
   472  		}
   473  	}()
   474  
   475  	if !s.Remote.Empty() {
   476  		// Legacy remote state is no longer supported. User must first
   477  		// migrate with Terraform 0.11 or earlier.
   478  		diags = diags.Append(tfdiags.Sourceless(
   479  			tfdiags.Error,
   480  			"Legacy remote state not supported",
   481  			"This working directory is configured for legacy remote state, which is no longer supported from Terraform v0.12 onwards. To migrate this environment, first run \"terraform init\" under a Terraform 0.11 release, and then upgrade Terraform again.",
   482  		))
   483  		return nil, diags
   484  	}
   485  
   486  	// This switch statement covers all the different combinations of
   487  	// configuring new backends, updating previously-configured backends, etc.
   488  	switch {
   489  	// No configuration set at all. Pure local state.
   490  	case c == nil && s.Backend.Empty():
   491  		log.Printf("[TRACE] Meta.Backend: using default local state only (no backend configuration, and no existing initialized backend)")
   492  		return nil, nil
   493  
   494  	// We're unsetting a backend (moving from backend => local)
   495  	case c == nil && !s.Backend.Empty():
   496  		log.Printf("[TRACE] Meta.Backend: previously-initialized %q backend is no longer present in config", s.Backend.Type)
   497  		if !opts.Init {
   498  			initReason := fmt.Sprintf(
   499  				"Unsetting the previously set backend %q",
   500  				s.Backend.Type)
   501  			m.backendInitRequired(initReason)
   502  			diags = diags.Append(errBackendInitRequired)
   503  			return nil, diags
   504  		}
   505  
   506  		return m.backend_c_r_S(c, cHash, sMgr, true)
   507  
   508  	// Configuring a backend for the first time.
   509  	case c != nil && s.Backend.Empty():
   510  		log.Printf("[TRACE] Meta.Backend: moving from default local state only to %q backend", c.Type)
   511  		if !opts.Init {
   512  			initReason := fmt.Sprintf(
   513  				"Initial configuration of the requested backend %q",
   514  				c.Type)
   515  			m.backendInitRequired(initReason)
   516  			diags = diags.Append(errBackendInitRequired)
   517  			return nil, diags
   518  		}
   519  
   520  		return m.backend_C_r_s(c, cHash, sMgr)
   521  
   522  	// Potentially changing a backend configuration
   523  	case c != nil && !s.Backend.Empty():
   524  		// We are not going to migrate if were not initializing and the hashes
   525  		// match indicating that the stored config is valid. If we are
   526  		// initializing, then we also assume the the backend config is OK if
   527  		// the hashes match, as long as we're not providing any new overrides.
   528  		if (uint64(cHash) == s.Backend.Hash) && (!opts.Init || opts.ConfigOverride == nil) {
   529  			log.Printf("[TRACE] Meta.Backend: using already-initialized, unchanged %q backend configuration", c.Type)
   530  			return m.backend_C_r_S_unchanged(c, cHash, sMgr)
   531  		}
   532  
   533  		// If our configuration is the same, then we're just initializing
   534  		// a previously configured remote backend.
   535  		if !m.backendConfigNeedsMigration(c, s.Backend) {
   536  			log.Printf("[TRACE] Meta.Backend: using already-initialized %q backend configuration", c.Type)
   537  			return m.backend_C_r_S_unchanged(c, cHash, sMgr)
   538  		}
   539  		log.Printf("[TRACE] Meta.Backend: backend configuration has changed (from type %q to type %q)", s.Backend.Type, c.Type)
   540  
   541  		if !opts.Init {
   542  			initReason := fmt.Sprintf(
   543  				"Backend configuration changed for %q",
   544  				c.Type)
   545  			m.backendInitRequired(initReason)
   546  			diags = diags.Append(errBackendInitRequired)
   547  			return nil, diags
   548  		}
   549  
   550  		log.Printf("[WARN] backend config has changed since last init")
   551  		return m.backend_C_r_S_changed(c, cHash, sMgr, true)
   552  
   553  	default:
   554  		diags = diags.Append(fmt.Errorf(
   555  			"Unhandled backend configuration state. This is a bug. Please\n"+
   556  				"report this error with the following information.\n\n"+
   557  				"Config Nil: %v\n"+
   558  				"Saved Backend Empty: %v\n",
   559  			c == nil, s.Backend.Empty(),
   560  		))
   561  		return nil, diags
   562  	}
   563  }
   564  
   565  // backendFromState returns the initialized (not configured) backend directly
   566  // from the state. This should be used only when a user runs `terraform init
   567  // -backend=false`. This function returns a local backend if there is no state
   568  // or no backend configured.
   569  func (m *Meta) backendFromState() (backend.Backend, tfdiags.Diagnostics) {
   570  	var diags tfdiags.Diagnostics
   571  	// Get the path to where we store a local cache of backend configuration
   572  	// if we're using a remote backend. This may not yet exist which means
   573  	// we haven't used a non-local backend before. That is okay.
   574  	statePath := filepath.Join(m.DataDir(), DefaultStateFilename)
   575  	sMgr := &state.LocalState{Path: statePath}
   576  	if err := sMgr.RefreshState(); err != nil {
   577  		diags = diags.Append(fmt.Errorf("Failed to load state: %s", err))
   578  		return nil, diags
   579  	}
   580  	s := sMgr.State()
   581  	if s == nil {
   582  		// no state, so return a local backend
   583  		log.Printf("[TRACE] Meta.Backend: backend has not previously been initialized in this working directory")
   584  		return backendLocal.New(), diags
   585  	}
   586  	if s.Backend == nil {
   587  		// s.Backend is nil, so return a local backend
   588  		log.Printf("[TRACE] Meta.Backend: working directory was previously initialized but has no backend (is using legacy remote state?)")
   589  		return backendLocal.New(), diags
   590  	}
   591  	log.Printf("[TRACE] Meta.Backend: working directory was previously initialized for %q backend", s.Backend.Type)
   592  
   593  	//backend init function
   594  	if s.Backend.Type == "" {
   595  		return backendLocal.New(), diags
   596  	}
   597  	f := backendInit.Backend(s.Backend.Type)
   598  	if f == nil {
   599  		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type))
   600  		return nil, diags
   601  	}
   602  	b := f()
   603  
   604  	// The configuration saved in the working directory state file is used
   605  	// in this case, since it will contain any additional values that
   606  	// were provided via -backend-config arguments on terraform init.
   607  	schema := b.ConfigSchema()
   608  	configVal, err := s.Backend.Config(schema)
   609  	if err != nil {
   610  		diags = diags.Append(tfdiags.Sourceless(
   611  			tfdiags.Error,
   612  			"Failed to decode current backend config",
   613  			fmt.Sprintf("The backend configuration created by the most recent run of \"terraform init\" could not be decoded: %s. The configuration may have been initialized by an earlier version that used an incompatible configuration structure. Run \"terraform init -reconfigure\" to force re-initialization of the backend.", err),
   614  		))
   615  		return nil, diags
   616  	}
   617  
   618  	// Validate the config and then configure the backend
   619  	newVal, validDiags := b.PrepareConfig(configVal)
   620  	diags = diags.Append(validDiags)
   621  	if validDiags.HasErrors() {
   622  		return nil, diags
   623  	}
   624  
   625  	configDiags := b.Configure(newVal)
   626  	diags = diags.Append(configDiags)
   627  	if configDiags.HasErrors() {
   628  		return nil, diags
   629  	}
   630  
   631  	return b, diags
   632  }
   633  
   634  //-------------------------------------------------------------------
   635  // Backend Config Scenarios
   636  //
   637  // The functions below cover handling all the various scenarios that
   638  // can exist when loading a backend. They are named in the format of
   639  // "backend_C_R_S" where C, R, S may be upper or lowercase. Lowercase
   640  // means it is false, uppercase means it is true. The full set of eight
   641  // possible cases is handled.
   642  //
   643  // The fields are:
   644  //
   645  //   * C - Backend configuration is set and changed in TF files
   646  //   * R - Legacy remote state is set
   647  //   * S - Backend configuration is set in the state
   648  //
   649  //-------------------------------------------------------------------
   650  
   651  // Unconfiguring a backend (moving from backend => local).
   652  func (m *Meta) backend_c_r_S(c *configs.Backend, cHash int, sMgr *state.LocalState, output bool) (backend.Backend, tfdiags.Diagnostics) {
   653  	s := sMgr.State()
   654  
   655  	// Get the backend type for output
   656  	backendType := s.Backend.Type
   657  
   658  	m.Ui.Output(fmt.Sprintf(strings.TrimSpace(outputBackendMigrateLocal), s.Backend.Type))
   659  
   660  	// Grab a purely local backend to get the local state if it exists
   661  	localB, diags := m.Backend(&BackendOpts{ForceLocal: true})
   662  	if diags.HasErrors() {
   663  		return nil, diags
   664  	}
   665  
   666  	// Initialize the configured backend
   667  	b, moreDiags := m.backend_C_r_S_unchanged(c, cHash, sMgr)
   668  	diags = diags.Append(moreDiags)
   669  	if moreDiags.HasErrors() {
   670  		return nil, diags
   671  	}
   672  
   673  	// Perform the migration
   674  	err := m.backendMigrateState(&backendMigrateOpts{
   675  		OneType: s.Backend.Type,
   676  		TwoType: "local",
   677  		One:     b,
   678  		Two:     localB,
   679  	})
   680  	if err != nil {
   681  		diags = diags.Append(err)
   682  		return nil, diags
   683  	}
   684  
   685  	// Remove the stored metadata
   686  	s.Backend = nil
   687  	if err := sMgr.WriteState(s); err != nil {
   688  		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
   689  		return nil, diags
   690  	}
   691  	if err := sMgr.PersistState(); err != nil {
   692  		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendClearSaved), err))
   693  		return nil, diags
   694  	}
   695  
   696  	if output {
   697  		m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
   698  			"[reset][green]\n\n"+
   699  				strings.TrimSpace(successBackendUnset), backendType)))
   700  	}
   701  
   702  	// Return no backend
   703  	return nil, diags
   704  }
   705  
   706  // Legacy remote state
   707  func (m *Meta) backend_c_R_s(c *configs.Backend, sMgr *state.LocalState) (backend.Backend, tfdiags.Diagnostics) {
   708  	var diags tfdiags.Diagnostics
   709  
   710  	m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
   711  
   712  	diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
   713  	return nil, diags
   714  }
   715  
   716  // Unsetting backend, saved backend, legacy remote state
   717  func (m *Meta) backend_c_R_S(c *configs.Backend, cHash int, sMgr *state.LocalState) (backend.Backend, tfdiags.Diagnostics) {
   718  	var diags tfdiags.Diagnostics
   719  
   720  	m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
   721  
   722  	diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
   723  	return nil, diags
   724  }
   725  
   726  // Configuring a backend for the first time with legacy remote state.
   727  func (m *Meta) backend_C_R_s(c *configs.Backend, sMgr *state.LocalState) (backend.Backend, tfdiags.Diagnostics) {
   728  	var diags tfdiags.Diagnostics
   729  
   730  	m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
   731  
   732  	diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
   733  	return nil, diags
   734  }
   735  
   736  // Configuring a backend for the first time.
   737  func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *state.LocalState) (backend.Backend, tfdiags.Diagnostics) {
   738  	// Get the backend
   739  	b, configVal, diags := m.backendInitFromConfig(c)
   740  	if diags.HasErrors() {
   741  		return nil, diags
   742  	}
   743  
   744  	// Grab a purely local backend to get the local state if it exists
   745  	localB, localBDiags := m.Backend(&BackendOpts{ForceLocal: true})
   746  	if localBDiags.HasErrors() {
   747  		diags = diags.Append(localBDiags)
   748  		return nil, diags
   749  	}
   750  
   751  	workspaces, err := localB.Workspaces()
   752  	if err != nil {
   753  		diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
   754  		return nil, diags
   755  	}
   756  
   757  	var localStates []state.State
   758  	for _, workspace := range workspaces {
   759  		localState, err := localB.StateMgr(workspace)
   760  		if err != nil {
   761  			diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
   762  			return nil, diags
   763  		}
   764  		if err := localState.RefreshState(); err != nil {
   765  			diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
   766  			return nil, diags
   767  		}
   768  
   769  		// We only care about non-empty states.
   770  		if localS := localState.State(); !localS.Empty() {
   771  			log.Printf("[TRACE] Meta.Backend: will need to migrate workspace states because of existing %q workspace", workspace)
   772  			localStates = append(localStates, localState)
   773  		} else {
   774  			log.Printf("[TRACE] Meta.Backend: ignoring local %q workspace because its state is empty", workspace)
   775  		}
   776  	}
   777  
   778  	if len(localStates) > 0 {
   779  		// Perform the migration
   780  		err = m.backendMigrateState(&backendMigrateOpts{
   781  			OneType: "local",
   782  			TwoType: c.Type,
   783  			One:     localB,
   784  			Two:     b,
   785  		})
   786  		if err != nil {
   787  			diags = diags.Append(err)
   788  			return nil, diags
   789  		}
   790  
   791  		// we usually remove the local state after migration to prevent
   792  		// confusion, but adding a default local backend block to the config
   793  		// can get us here too. Don't delete our state if the old and new paths
   794  		// are the same.
   795  		erase := true
   796  		if newLocalB, ok := b.(*backendLocal.Local); ok {
   797  			if localB, ok := localB.(*backendLocal.Local); ok {
   798  				if newLocalB.PathsConflictWith(localB) {
   799  					erase = false
   800  					log.Printf("[TRACE] Meta.Backend: both old and new backends share the same local state paths, so not erasing old state")
   801  				}
   802  			}
   803  		}
   804  
   805  		if erase {
   806  			log.Printf("[TRACE] Meta.Backend: removing old state snapshots from old backend")
   807  			for _, localState := range localStates {
   808  				// We always delete the local state, unless that was our new state too.
   809  				if err := localState.WriteState(nil); err != nil {
   810  					diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
   811  					return nil, diags
   812  				}
   813  				if err := localState.PersistState(); err != nil {
   814  					diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
   815  					return nil, diags
   816  				}
   817  			}
   818  		}
   819  	}
   820  
   821  	if m.stateLock {
   822  		stateLocker := clistate.NewLocker(context.Background(), m.stateLockTimeout, m.Ui, m.Colorize())
   823  		if err := stateLocker.Lock(sMgr, "backend from plan"); err != nil {
   824  			diags = diags.Append(fmt.Errorf("Error locking state: %s", err))
   825  			return nil, diags
   826  		}
   827  		defer stateLocker.Unlock(nil)
   828  	}
   829  
   830  	configJSON, err := ctyjson.Marshal(configVal, b.ConfigSchema().ImpliedType())
   831  	if err != nil {
   832  		diags = diags.Append(fmt.Errorf("Can't serialize backend configuration as JSON: %s", err))
   833  		return nil, diags
   834  	}
   835  
   836  	// Store the metadata in our saved state location
   837  	s := sMgr.State()
   838  	if s == nil {
   839  		s = terraform.NewState()
   840  	}
   841  	s.Backend = &terraform.BackendState{
   842  		Type:      c.Type,
   843  		ConfigRaw: json.RawMessage(configJSON),
   844  		Hash:      uint64(cHash),
   845  	}
   846  
   847  	if err := sMgr.WriteState(s); err != nil {
   848  		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
   849  		return nil, diags
   850  	}
   851  	if err := sMgr.PersistState(); err != nil {
   852  		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
   853  		return nil, diags
   854  	}
   855  
   856  	// By now the backend is successfully configured.
   857  	m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
   858  		"[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type)))
   859  
   860  	return b, diags
   861  }
   862  
   863  // Changing a previously saved backend.
   864  func (m *Meta) backend_C_r_S_changed(c *configs.Backend, cHash int, sMgr *state.LocalState, output bool) (backend.Backend, tfdiags.Diagnostics) {
   865  	if output {
   866  		// Notify the user
   867  		m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
   868  			"[reset]%s\n\n",
   869  			strings.TrimSpace(outputBackendReconfigure))))
   870  	}
   871  
   872  	// Get the old state
   873  	s := sMgr.State()
   874  
   875  	// Get the backend
   876  	b, configVal, diags := m.backendInitFromConfig(c)
   877  	if diags.HasErrors() {
   878  		return nil, diags
   879  	}
   880  
   881  	// no need to confuse the user if the backend types are the same
   882  	if s.Backend.Type != c.Type {
   883  		m.Ui.Output(strings.TrimSpace(fmt.Sprintf(outputBackendMigrateChange, s.Backend.Type, c.Type)))
   884  	}
   885  
   886  	// Grab the existing backend
   887  	oldB, oldBDiags := m.backend_C_r_S_unchanged(c, cHash, sMgr)
   888  	diags = diags.Append(oldBDiags)
   889  	if oldBDiags.HasErrors() {
   890  		return nil, diags
   891  	}
   892  
   893  	// Perform the migration
   894  	err := m.backendMigrateState(&backendMigrateOpts{
   895  		OneType: s.Backend.Type,
   896  		TwoType: c.Type,
   897  		One:     oldB,
   898  		Two:     b,
   899  	})
   900  	if err != nil {
   901  		diags = diags.Append(err)
   902  		return nil, diags
   903  	}
   904  
   905  	if m.stateLock {
   906  		stateLocker := clistate.NewLocker(context.Background(), m.stateLockTimeout, m.Ui, m.Colorize())
   907  		if err := stateLocker.Lock(sMgr, "backend from plan"); err != nil {
   908  			diags = diags.Append(fmt.Errorf("Error locking state: %s", err))
   909  			return nil, diags
   910  		}
   911  		defer stateLocker.Unlock(nil)
   912  	}
   913  
   914  	configJSON, err := ctyjson.Marshal(configVal, b.ConfigSchema().ImpliedType())
   915  	if err != nil {
   916  		diags = diags.Append(fmt.Errorf("Can't serialize backend configuration as JSON: %s", err))
   917  		return nil, diags
   918  	}
   919  
   920  	// Update the backend state
   921  	s = sMgr.State()
   922  	if s == nil {
   923  		s = terraform.NewState()
   924  	}
   925  	s.Backend = &terraform.BackendState{
   926  		Type:      c.Type,
   927  		ConfigRaw: json.RawMessage(configJSON),
   928  		Hash:      uint64(cHash),
   929  	}
   930  
   931  	if err := sMgr.WriteState(s); err != nil {
   932  		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
   933  		return nil, diags
   934  	}
   935  	if err := sMgr.PersistState(); err != nil {
   936  		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
   937  		return nil, diags
   938  	}
   939  
   940  	if output {
   941  		m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
   942  			"[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type)))
   943  	}
   944  
   945  	return b, diags
   946  }
   947  
   948  // Initiailizing an unchanged saved backend
   949  func (m *Meta) backend_C_r_S_unchanged(c *configs.Backend, cHash int, sMgr *state.LocalState) (backend.Backend, tfdiags.Diagnostics) {
   950  	var diags tfdiags.Diagnostics
   951  
   952  	s := sMgr.State()
   953  
   954  	// it's possible for a backend to be unchanged, and the config itself to
   955  	// have changed by moving a parameter from the config to `-backend-config`
   956  	// In this case we only need to update the Hash.
   957  	if c != nil && s.Backend.Hash != uint64(cHash) {
   958  		s.Backend.Hash = uint64(cHash)
   959  		if err := sMgr.WriteState(s); err != nil {
   960  			diags = diags.Append(err)
   961  			return nil, diags
   962  		}
   963  	}
   964  
   965  	// Get the backend
   966  	f := backendInit.Backend(s.Backend.Type)
   967  	if f == nil {
   968  		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Backend.Type))
   969  		return nil, diags
   970  	}
   971  	b := f()
   972  
   973  	// The configuration saved in the working directory state file is used
   974  	// in this case, since it will contain any additional values that
   975  	// were provided via -backend-config arguments on terraform init.
   976  	schema := b.ConfigSchema()
   977  	configVal, err := s.Backend.Config(schema)
   978  	if err != nil {
   979  		diags = diags.Append(tfdiags.Sourceless(
   980  			tfdiags.Error,
   981  			"Failed to decode current backend config",
   982  			fmt.Sprintf("The backend configuration created by the most recent run of \"terraform init\" could not be decoded: %s. The configuration may have been initialized by an earlier version that used an incompatible configuration structure. Run \"terraform init -reconfigure\" to force re-initialization of the backend.", err),
   983  		))
   984  		return nil, diags
   985  	}
   986  
   987  	// Validate the config and then configure the backend
   988  	newVal, validDiags := b.PrepareConfig(configVal)
   989  	diags = diags.Append(validDiags)
   990  	if validDiags.HasErrors() {
   991  		return nil, diags
   992  	}
   993  
   994  	configDiags := b.Configure(newVal)
   995  	diags = diags.Append(configDiags)
   996  	if configDiags.HasErrors() {
   997  		return nil, diags
   998  	}
   999  
  1000  	return b, diags
  1001  }
  1002  
  1003  // Initiailizing a changed saved backend with legacy remote state.
  1004  func (m *Meta) backend_C_R_S_changed(c *configs.Backend, sMgr *state.LocalState) (backend.Backend, tfdiags.Diagnostics) {
  1005  	var diags tfdiags.Diagnostics
  1006  
  1007  	m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
  1008  
  1009  	diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
  1010  	return nil, diags
  1011  }
  1012  
  1013  // Initiailizing an unchanged saved backend with legacy remote state.
  1014  func (m *Meta) backend_C_R_S_unchanged(c *configs.Backend, sMgr *state.LocalState, output bool) (backend.Backend, tfdiags.Diagnostics) {
  1015  	var diags tfdiags.Diagnostics
  1016  
  1017  	m.Ui.Error(strings.TrimSpace(errBackendLegacy) + "\n")
  1018  
  1019  	diags = diags.Append(fmt.Errorf("Cannot initialize legacy remote state"))
  1020  	return nil, diags
  1021  }
  1022  
  1023  //-------------------------------------------------------------------
  1024  // Reusable helper functions for backend management
  1025  //-------------------------------------------------------------------
  1026  
  1027  // backendConfigNeedsMigration returns true if migration might be required to
  1028  // move from the configured backend to the given cached backend config.
  1029  //
  1030  // This must be called with the synthetic *configs.Backend that results from
  1031  // merging in any command-line options for correct behavior.
  1032  //
  1033  // If either the given configuration or cached configuration are invalid then
  1034  // this function will conservatively assume that migration is required,
  1035  // expecting that the migration code will subsequently deal with the same
  1036  // errors.
  1037  func (m *Meta) backendConfigNeedsMigration(c *configs.Backend, s *terraform.BackendState) bool {
  1038  	if s == nil || s.Empty() {
  1039  		log.Print("[TRACE] backendConfigNeedsMigration: no cached config, so migration is required")
  1040  		return true
  1041  	}
  1042  	if c.Type != s.Type {
  1043  		log.Printf("[TRACE] backendConfigNeedsMigration: type changed from %q to %q, so migration is required", s.Type, c.Type)
  1044  		return true
  1045  	}
  1046  
  1047  	// We need the backend's schema to do our comparison here.
  1048  	f := backendInit.Backend(c.Type)
  1049  	if f == nil {
  1050  		log.Printf("[TRACE] backendConfigNeedsMigration: no backend of type %q, which migration codepath must handle", c.Type)
  1051  		return true // let the migration codepath deal with the missing backend
  1052  	}
  1053  	b := f()
  1054  
  1055  	schema := b.ConfigSchema()
  1056  	decSpec := schema.NoneRequired().DecoderSpec()
  1057  	givenVal, diags := hcldec.Decode(c.Config, decSpec, nil)
  1058  	if diags.HasErrors() {
  1059  		log.Printf("[TRACE] backendConfigNeedsMigration: failed to decode given config; migration codepath must handle problem: %s", diags.Error())
  1060  		return true // let the migration codepath deal with these errors
  1061  	}
  1062  
  1063  	cachedVal, err := s.Config(schema)
  1064  	if err != nil {
  1065  		log.Printf("[TRACE] backendConfigNeedsMigration: failed to decode cached config; migration codepath must handle problem: %s", err)
  1066  		return true // let the migration codepath deal with the error
  1067  	}
  1068  
  1069  	// If we get all the way down here then it's the exact equality of the
  1070  	// two decoded values that decides our outcome. It's safe to use RawEquals
  1071  	// here (rather than Equals) because we know that unknown values can
  1072  	// never appear in backend configurations.
  1073  	if cachedVal.RawEquals(givenVal) {
  1074  		log.Print("[TRACE] backendConfigNeedsMigration: given configuration matches cached configuration, so no migration is required")
  1075  		return false
  1076  	}
  1077  	log.Print("[TRACE] backendConfigNeedsMigration: configuration values have changed, so migration is required")
  1078  	return true
  1079  }
  1080  
  1081  func (m *Meta) backendInitFromConfig(c *configs.Backend) (backend.Backend, cty.Value, tfdiags.Diagnostics) {
  1082  	var diags tfdiags.Diagnostics
  1083  
  1084  	// Get the backend
  1085  	f := backendInit.Backend(c.Type)
  1086  	if f == nil {
  1087  		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendNewUnknown), c.Type))
  1088  		return nil, cty.NilVal, diags
  1089  	}
  1090  	b := f()
  1091  
  1092  	schema := b.ConfigSchema()
  1093  	decSpec := schema.NoneRequired().DecoderSpec()
  1094  	configVal, hclDiags := hcldec.Decode(c.Config, decSpec, nil)
  1095  	diags = diags.Append(hclDiags)
  1096  	if hclDiags.HasErrors() {
  1097  		return nil, cty.NilVal, diags
  1098  	}
  1099  
  1100  	// TODO: test
  1101  	if m.Input() {
  1102  		var err error
  1103  		configVal, err = m.inputForSchema(configVal, schema)
  1104  		if err != nil {
  1105  			diags = diags.Append(fmt.Errorf("Error asking for input to configure backend %q: %s", c.Type, err))
  1106  		}
  1107  
  1108  		// We get an unknown here if the if the user aborted input, but we can't
  1109  		// turn that into a config value, so set it to null and let the provider
  1110  		// handle it in PrepareConfig.
  1111  		if !configVal.IsKnown() {
  1112  			configVal = cty.NullVal(configVal.Type())
  1113  		}
  1114  	}
  1115  
  1116  	newVal, validateDiags := b.PrepareConfig(configVal)
  1117  	diags = diags.Append(validateDiags.InConfigBody(c.Config))
  1118  	if validateDiags.HasErrors() {
  1119  		return nil, cty.NilVal, diags
  1120  	}
  1121  
  1122  	configureDiags := b.Configure(newVal)
  1123  	diags = diags.Append(configureDiags.InConfigBody(c.Config))
  1124  
  1125  	return b, configVal, diags
  1126  }
  1127  
  1128  func (m *Meta) backendInitFromSaved(s *terraform.BackendState) (backend.Backend, tfdiags.Diagnostics) {
  1129  	var diags tfdiags.Diagnostics
  1130  
  1131  	// Get the backend
  1132  	f := backendInit.Backend(s.Type)
  1133  	if f == nil {
  1134  		diags = diags.Append(fmt.Errorf(strings.TrimSpace(errBackendSavedUnknown), s.Type))
  1135  		return nil, diags
  1136  	}
  1137  	b := f()
  1138  
  1139  	schema := b.ConfigSchema()
  1140  	configVal, err := s.Config(schema)
  1141  	if err != nil {
  1142  		diags = diags.Append(errwrap.Wrapf("saved backend configuration is invalid: {{err}}", err))
  1143  		return nil, diags
  1144  	}
  1145  
  1146  	newVal, validateDiags := b.PrepareConfig(configVal)
  1147  	diags = diags.Append(validateDiags)
  1148  	if validateDiags.HasErrors() {
  1149  		return nil, diags
  1150  	}
  1151  
  1152  	configureDiags := b.Configure(newVal)
  1153  	diags = diags.Append(configureDiags)
  1154  
  1155  	return b, diags
  1156  }
  1157  
  1158  func (m *Meta) backendInitRequired(reason string) {
  1159  	m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
  1160  		"[reset]"+strings.TrimSpace(errBackendInit)+"\n", reason)))
  1161  }
  1162  
  1163  //-------------------------------------------------------------------
  1164  // Output constants and initialization code
  1165  //-------------------------------------------------------------------
  1166  
  1167  // errBackendInitRequired is the final error message shown when reinit
  1168  // is required for some reason. The error message includes the reason.
  1169  var errBackendInitRequired = errors.New(
  1170  	"Initialization required. Please see the error message above.")
  1171  
  1172  const errBackendLegacyConfig = `
  1173  One or more errors occurred while configuring the legacy remote state.
  1174  If fixing these errors requires changing your remote state configuration,
  1175  you must switch your configuration to the new remote backend configuration.
  1176  You can learn more about remote backends at the URL below:
  1177  
  1178  https://www.terraform.io/docs/backends/index.html
  1179  
  1180  The error(s) configuring the legacy remote state:
  1181  
  1182  %s
  1183  `
  1184  
  1185  const errBackendLegacyUnknown = `
  1186  The legacy remote state type %q could not be found.
  1187  
  1188  Terraform 0.9.0 shipped with backwards compatibility for all built-in
  1189  legacy remote state types. This error may mean that you were using a
  1190  custom Terraform build that perhaps supported a different type of
  1191  remote state.
  1192  
  1193  Please check with the creator of the remote state above and try again.
  1194  `
  1195  
  1196  const errBackendLocalRead = `
  1197  Error reading local state: %s
  1198  
  1199  Terraform is trying to read your local state to determine if there is
  1200  state to migrate to your newly configured backend. Terraform can't continue
  1201  without this check because that would risk losing state. Please resolve the
  1202  error above and try again.
  1203  `
  1204  
  1205  const errBackendMigrateLocalDelete = `
  1206  Error deleting local state after migration: %s
  1207  
  1208  Your local state is deleted after successfully migrating it to the newly
  1209  configured backend. As part of the deletion process, a backup is made at
  1210  the standard backup path unless explicitly asked not to. To cleanly operate
  1211  with a backend, we must delete the local state file. Please resolve the
  1212  issue above and retry the command.
  1213  `
  1214  
  1215  const errBackendMigrateNew = `
  1216  Error migrating local state to backend: %s
  1217  
  1218  Your local state remains intact and unmodified. Please resolve the error
  1219  above and try again.
  1220  `
  1221  
  1222  const errBackendNewConfig = `
  1223  Error configuring the backend %q: %s
  1224  
  1225  Please update the configuration in your Terraform files to fix this error
  1226  then run this command again.
  1227  `
  1228  
  1229  const errBackendNewRead = `
  1230  Error reading newly configured backend state: %s
  1231  
  1232  Terraform is trying to read the state from your newly configured backend
  1233  to determine the copy process for your existing state. Backends are expected
  1234  to not error even if there is no state yet written. Please resolve the
  1235  error above and try again.
  1236  `
  1237  
  1238  const errBackendNewUnknown = `
  1239  The backend %q could not be found.
  1240  
  1241  This is the backend specified in your Terraform configuration file.
  1242  This error could be a simple typo in your configuration, but it can also
  1243  be caused by using a Terraform version that doesn't support the specified
  1244  backend type. Please check your configuration and your Terraform version.
  1245  
  1246  If you'd like to run Terraform and store state locally, you can fix this
  1247  error by removing the backend configuration from your configuration.
  1248  `
  1249  
  1250  const errBackendNoExistingWorkspaces = `
  1251  No existing workspaces.
  1252  
  1253  Use the "terraform workspace" command to create and select a new workspace.
  1254  If the backend already contains existing workspaces, you may need to update
  1255  the backend configuration.
  1256  `
  1257  
  1258  const errBackendRemoteRead = `
  1259  Error reading backend state: %s
  1260  
  1261  Terraform is trying to read the state from your configured backend to
  1262  determine if there is any migration steps necessary. Terraform can't continue
  1263  without this check because that would risk losing state. Please resolve the
  1264  error above and try again.
  1265  `
  1266  
  1267  const errBackendSavedConfig = `
  1268  Error configuring the backend %q: %s
  1269  
  1270  Please update the configuration in your Terraform files to fix this error.
  1271  If you'd like to update the configuration interactively without storing
  1272  the values in your configuration, run "terraform init".
  1273  `
  1274  
  1275  const errBackendSavedUnsetConfig = `
  1276  Error configuring the existing backend %q: %s
  1277  
  1278  Terraform must configure the existing backend in order to copy the state
  1279  from the existing backend, as requested. Please resolve the error and try
  1280  again. If you choose to not copy the existing state, Terraform will not
  1281  configure the backend. If the configuration is invalid, please update your
  1282  Terraform configuration with proper configuration for this backend first
  1283  before unsetting the backend.
  1284  `
  1285  
  1286  const errBackendSavedUnknown = `
  1287  The backend %q could not be found.
  1288  
  1289  This is the backend that this Terraform environment is configured to use
  1290  both in your configuration and saved locally as your last-used backend.
  1291  If it isn't found, it could mean an alternate version of Terraform was
  1292  used with this configuration. Please use the proper version of Terraform that
  1293  contains support for this backend.
  1294  
  1295  If you'd like to force remove this backend, you must update your configuration
  1296  to not use the backend and run "terraform init" (or any other command) again.
  1297  `
  1298  
  1299  const errBackendClearLegacy = `
  1300  Error clearing the legacy remote state configuration: %s
  1301  
  1302  Terraform completed configuring your backend. It is now safe to remove
  1303  the legacy remote state configuration, but an error occurred while trying
  1304  to do so. Please look at the error above, resolve it, and try again.
  1305  `
  1306  
  1307  const errBackendClearSaved = `
  1308  Error clearing the backend configuration: %s
  1309  
  1310  Terraform removes the saved backend configuration when you're removing a
  1311  configured backend. This must be done so future Terraform runs know to not
  1312  use the backend configuration. Please look at the error above, resolve it,
  1313  and try again.
  1314  `
  1315  
  1316  const errBackendInit = `
  1317  [reset][bold][yellow]Backend reinitialization required. Please run "terraform init".[reset]
  1318  [yellow]Reason: %s
  1319  
  1320  The "backend" is the interface that Terraform uses to store state,
  1321  perform operations, etc. If this message is showing up, it means that the
  1322  Terraform configuration you're using is using a custom configuration for
  1323  the Terraform backend.
  1324  
  1325  Changes to backend configurations require reinitialization. This allows
  1326  Terraform to setup the new configuration, copy existing state, etc. This is
  1327  only done during "terraform init". Please run that command now then try again.
  1328  
  1329  If the change reason above is incorrect, please verify your configuration
  1330  hasn't changed and try again. At this point, no changes to your existing
  1331  configuration or state have been made.
  1332  `
  1333  
  1334  const errBackendWriteSaved = `
  1335  Error saving the backend configuration: %s
  1336  
  1337  Terraform saves the complete backend configuration in a local file for
  1338  configuring the backend on future operations. This cannot be disabled. Errors
  1339  are usually due to simple file permission errors. Please look at the error
  1340  above, resolve it, and try again.
  1341  `
  1342  
  1343  const errBackendPlanBoth = `
  1344  The plan file contained both a legacy remote state and backend configuration.
  1345  This is not allowed. Please recreate the plan file with the latest version of
  1346  Terraform.
  1347  `
  1348  
  1349  const errBackendPlanLineageDiff = `
  1350  The plan file contains a state with a differing lineage than the current
  1351  state. By continuing, your current state would be overwritten by the state
  1352  in the plan. Please either update the plan with the latest state or delete
  1353  your current state and try again.
  1354  
  1355  "Lineage" is a unique identifier generated only once on the creation of
  1356  a new, empty state. If these values differ, it means they were created new
  1357  at different times. Therefore, Terraform must assume that they're completely
  1358  different states.
  1359  
  1360  The most common cause of seeing this error is using a plan that was
  1361  created against a different state. Perhaps the plan is very old and the
  1362  state has since been recreated, or perhaps the plan was against a completely
  1363  different infrastructure.
  1364  `
  1365  
  1366  const errBackendPlanStateFlag = `
  1367  The -state and -state-out flags cannot be set with a plan that has a remote
  1368  state. The plan itself contains the configuration for the remote backend to
  1369  store state. The state will be written there for consistency.
  1370  
  1371  If you wish to change this behavior, please create a plan from local state.
  1372  You may use the state flags with plans from local state to affect where
  1373  the final state is written.
  1374  `
  1375  
  1376  const errBackendPlanOlder = `
  1377  This plan was created against an older state than is current. Please create
  1378  a new plan file against the latest state and try again.
  1379  
  1380  Terraform doesn't allow you to run plans that were created from older
  1381  states since it doesn't properly represent the latest changes Terraform
  1382  may have made, and can result in unsafe behavior.
  1383  
  1384  Plan Serial:    %[1]d
  1385  Current Serial: %[2]d
  1386  `
  1387  
  1388  const outputBackendMigrateChange = `
  1389  Terraform detected that the backend type changed from %q to %q.
  1390  `
  1391  
  1392  const outputBackendMigrateLegacy = `
  1393  Terraform detected legacy remote state.
  1394  `
  1395  
  1396  const outputBackendMigrateLocal = `
  1397  Terraform has detected you're unconfiguring your previously set %q backend.
  1398  `
  1399  
  1400  const outputBackendConfigureWithLegacy = `
  1401  [reset][bold]New backend configuration detected with legacy remote state![reset]
  1402  
  1403  Terraform has detected that you're attempting to configure a new backend.
  1404  At the same time, legacy remote state configuration was found. Terraform will
  1405  first configure the new backend, and then ask if you'd like to migrate
  1406  your remote state to the new backend.
  1407  `
  1408  
  1409  const outputBackendReconfigure = `
  1410  [reset][bold]Backend configuration changed![reset]
  1411  
  1412  Terraform has detected that the configuration specified for the backend
  1413  has changed. Terraform will now check for existing state in the backends.
  1414  `
  1415  
  1416  const outputBackendSavedWithLegacy = `
  1417  [reset][bold]Legacy remote state was detected![reset]
  1418  
  1419  Terraform has detected you still have legacy remote state enabled while
  1420  also having a backend configured. Terraform will now ask if you want to
  1421  migrate your legacy remote state data to the configured backend.
  1422  `
  1423  
  1424  const outputBackendSavedWithLegacyChanged = `
  1425  [reset][bold]Legacy remote state was detected while also changing your current backend!reset]
  1426  
  1427  Terraform has detected that you have legacy remote state, a configured
  1428  current backend, and you're attempting to reconfigure your backend. To handle
  1429  all of these changes, Terraform will first reconfigure your backend. After
  1430  this, Terraform will handle optionally copying your legacy remote state
  1431  into the newly configured backend.
  1432  `
  1433  
  1434  const outputBackendUnsetWithLegacy = `
  1435  [reset][bold]Detected a request to unset the backend with legacy remote state present![reset]
  1436  
  1437  Terraform has detected that you're attempting to unset a previously configured
  1438  backend (by not having the "backend" configuration set in your Terraform files).
  1439  At the same time, legacy remote state was detected. To handle this complex
  1440  scenario, Terraform will first unset your configured backend, and then
  1441  ask you how to handle the legacy remote state. This will be multi-step
  1442  process.
  1443  `
  1444  
  1445  const successBackendLegacyUnset = `
  1446  Terraform has successfully migrated from legacy remote state to your
  1447  configured backend (%q).
  1448  `
  1449  
  1450  const successBackendReconfigureWithLegacy = `
  1451  Terraform has successfully reconfigured your backend and migrate
  1452  from legacy remote state to the new backend.
  1453  `
  1454  
  1455  const successBackendUnset = `
  1456  Successfully unset the backend %q. Terraform will now operate locally.
  1457  `
  1458  
  1459  const successBackendSet = `
  1460  Successfully configured the backend %q! Terraform will automatically
  1461  use this backend unless the backend configuration changes.
  1462  `
  1463  
  1464  const errBackendLegacy = `
  1465  This working directory is configured to use the legacy remote state features
  1466  from Terraform 0.8 or earlier. Remote state changed significantly in Terraform
  1467  0.9 and the automatic upgrade mechanism has now been removed.
  1468  
  1469  To upgrade, please first use Terraform v0.11 to complete the upgrade steps:
  1470      https://www.terraform.io/docs/backends/legacy-0-8.html
  1471  `