@@ -74,18 +74,9 @@ type BackendOpts struct {
7474 // the root module, or nil if no such block is present.
7575 StateStoreConfig * configs.StateStore
7676
77- // ProvidersFactory contains a factory for creating instances of the
78- // provider used for pluggable state storage. Each call created a new instance,
79- // so be conscious of when the provider needs to be configured, etc.
80- //
81- // This will only be set if the configuration contains a state_store block.
82- ProviderFactory providers.Factory
83-
8477 // Locks allows state-migration logic to detect when the provider used for pluggable state storage
8578 // during the last init (i.e. what's in the backend state file) is mismatched with the provider
8679 // version in use currently.
87- //
88- // This will only be set if the configuration contains a state_store block.
8980 Locks * depsfile.Locks
9081
9182 // ConfigOverride is an hcl.Body that, if non-nil, will be used with
@@ -591,16 +582,13 @@ func (m *Meta) stateStoreConfig(opts *BackendOpts) (*configs.StateStore, int, tf
591582 return nil , 0 , diags
592583 }
593584
594- // Check - is the state store type in the config supported by the provider?
595- if opts .ProviderFactory == nil {
596- diags = diags .Append (& hcl.Diagnostic {
597- Severity : hcl .DiagError ,
598- Summary : "Missing provider details when configuring state store" ,
599- Detail : "Terraform attempted to configure a state store and no provider factory was available to launch it. This is a bug in Terraform and should be reported." ,
600- })
585+ pFactory , pDiags := m .GetStateStoreProviderFactory (opts .StateStoreConfig , opts .Locks )
586+ diags = diags .Append (pDiags )
587+ if pDiags .HasErrors () {
601588 return nil , 0 , diags
602589 }
603- provider , err := opts .ProviderFactory ()
590+
591+ provider , err := pFactory ()
604592 if err != nil {
605593 diags = diags .Append (fmt .Errorf ("error when obtaining provider instance during state store initialization: %w" , err ))
606594 return nil , 0 , diags
@@ -955,7 +943,7 @@ func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Di
955943 // AND we're not providing any overrides. An override can mean a change overriding an unchanged backend block (indicated by the hash value).
956944 if (uint64 (cHash ) == s .StateStore .Hash ) && (! opts .Init || opts .ConfigOverride == nil ) {
957945 log .Printf ("[TRACE] Meta.Backend: using already-initialized, unchanged %q state_store configuration" , stateStoreConfig .Type )
958- savedStateStore , sssDiags := m .savedStateStore (sMgr , opts . ProviderFactory )
946+ savedStateStore , sssDiags := m .savedStateStore (sMgr )
959947 diags = diags .Append (sssDiags )
960948 // Verify that selected workspace exist. Otherwise prompt user to create one
961949 if opts .Init && savedStateStore != nil {
@@ -1601,43 +1589,37 @@ func (m *Meta) backend(configPath string, viewType arguments.ViewType) (backendr
16011589 return nil , diags
16021590 }
16031591
1592+ locks , lDiags := m .lockedDependencies ()
1593+ diags = diags .Append (lDiags )
1594+ if lDiags .HasErrors () {
1595+ return nil , diags
1596+ }
1597+
16041598 var opts * BackendOpts
16051599 switch {
16061600 case root .Backend != nil :
16071601 opts = & BackendOpts {
16081602 BackendConfig : root .Backend ,
1603+ Locks : locks ,
16091604 ViewType : viewType ,
16101605 }
16111606 case root .CloudConfig != nil :
16121607 backendConfig := root .CloudConfig .ToBackendConfig ()
16131608 opts = & BackendOpts {
16141609 BackendConfig : & backendConfig ,
1610+ Locks : locks ,
16151611 ViewType : viewType ,
16161612 }
16171613 case root .StateStore != nil :
1618- // In addition to config, use of a state_store requires
1619- // provider factory and provider locks data
1620- locks , lDiags := m .lockedDependencies ()
1621- diags = diags .Append (lDiags )
1622- if lDiags .HasErrors () {
1623- return nil , diags
1624- }
1625-
1626- factory , fDiags := m .GetStateStoreProviderFactory (root .StateStore , locks )
1627- diags = diags .Append (fDiags )
1628- if fDiags .HasErrors () {
1629- return nil , diags
1630- }
1631-
16321614 opts = & BackendOpts {
16331615 StateStoreConfig : root .StateStore ,
1634- ProviderFactory : factory ,
16351616 Locks : locks ,
16361617 ViewType : viewType ,
16371618 }
16381619 default :
16391620 // there is no config; defaults to local state storage
16401621 opts = & BackendOpts {
1622+ Locks : locks ,
16411623 ViewType : viewType ,
16421624 }
16431625 }
@@ -1716,7 +1698,7 @@ func (m *Meta) stateStore_C_s(c *configs.StateStore, stateStoreHash int, backend
17161698 }
17171699
17181700 // Get the state store as an instance of backend.Backend
1719- b , storeConfigVal , providerConfigVal , moreDiags := m .stateStoreInitFromConfig (c , opts .ProviderFactory )
1701+ b , storeConfigVal , providerConfigVal , moreDiags := m .stateStoreInitFromConfig (c , opts .Locks )
17201702 diags = diags .Append (moreDiags )
17211703 if diags .HasErrors () {
17221704 return nil , diags
@@ -1953,22 +1935,28 @@ func (m *Meta) createDefaultWorkspace(c *configs.StateStore, b backend.Backend)
19531935}
19541936
19551937// Initializing a saved state store from the backend state file (aka 'cache file', aka 'legacy state file')
1956- func (m * Meta ) savedStateStore (sMgr * clistate.LocalState , factory providers. Factory ) (backend.Backend , tfdiags.Diagnostics ) {
1938+ func (m * Meta ) savedStateStore (sMgr * clistate.LocalState ) (backend.Backend , tfdiags.Diagnostics ) {
19571939 // We're preparing a state_store version of backend.Backend.
19581940 //
19591941 // The provider and state store will be configured using the backend state file.
19601942
19611943 var diags tfdiags.Diagnostics
19621944 var b backend.Backend
19631945
1964- if factory == nil {
1965- diags = diags .Append (& hcl.Diagnostic {
1966- Severity : hcl .DiagError ,
1967- Summary : "Missing provider details when configuring state store" ,
1968- Detail : "Terraform attempted to configure a state store and no provider factory was available to launch it. This is a bug in Terraform and should be reported." ,
1969- })
1946+ s := sMgr .State ()
1947+
1948+ locks , lDiags := m .lockedDependencies ()
1949+ diags = diags .Append (lDiags )
1950+ if lDiags .HasErrors () {
19701951 return nil , diags
19711952 }
1953+
1954+ factory , pDiags := m .StateStoreProviderFactoryFromConfigState (s .StateStore , locks )
1955+ diags = diags .Append (pDiags )
1956+ if pDiags .HasErrors () {
1957+ return nil , diags
1958+ }
1959+
19721960 provider , err := factory ()
19731961 if err != nil {
19741962 diags = diags .Append (fmt .Errorf ("error when obtaining provider instance during state store initialization: %w" , err ))
@@ -1978,7 +1966,6 @@ func (m *Meta) savedStateStore(sMgr *clistate.LocalState, factory providers.Fact
19781966 // running provider instance inside the returned backend.Backend instance.
19791967 // Stopping the provider process is the responsibility of the calling code.
19801968
1981- s := sMgr .State ()
19821969 resp := provider .GetProviderSchema ()
19831970
19841971 if len (resp .StateStores ) == 0 {
@@ -2256,17 +2243,15 @@ func (m *Meta) backendInitFromConfig(c *configs.Backend) (backend.Backend, cty.V
22562243//
22572244// NOTE: the backend version of this method, `backendInitFromConfig`, prompts users for input if any required fields
22582245// are missing from the backend config. In `stateStoreInitFromConfig` we don't do this, and instead users will see an error.
2259- func (m * Meta ) stateStoreInitFromConfig (c * configs.StateStore , factory providers. Factory ) (backend.Backend , cty.Value , cty.Value , tfdiags.Diagnostics ) {
2246+ func (m * Meta ) stateStoreInitFromConfig (c * configs.StateStore , locks * depsfile. Locks ) (backend.Backend , cty.Value , cty.Value , tfdiags.Diagnostics ) {
22602247 var diags tfdiags.Diagnostics
22612248
2262- if factory == nil {
2263- diags = diags .Append (& hcl.Diagnostic {
2264- Severity : hcl .DiagError ,
2265- Summary : "Missing provider details when configuring state store" ,
2266- Detail : "Terraform attempted to configure a state store and no provider factory was available to launch it. This is a bug in Terraform and should be reported." ,
2267- })
2249+ factory , pDiags := m .GetStateStoreProviderFactory (c , locks )
2250+ diags = diags .Append (pDiags )
2251+ if pDiags .HasErrors () {
22682252 return nil , cty .NilVal , cty .NilVal , diags
22692253 }
2254+
22702255 provider , err := factory ()
22712256 if err != nil {
22722257 diags = diags .Append (fmt .Errorf ("error when obtaining provider instance during state store initialization: %w" , err ))
@@ -2547,6 +2532,56 @@ func (m *Meta) GetStateStoreProviderFactory(config *configs.StateStore, locks *d
25472532 return factory , diags
25482533}
25492534
2535+ func (m * Meta ) StateStoreProviderFactoryFromConfigState (cfgState * workdir.StateStoreConfigState , locks * depsfile.Locks ) (providers.Factory , tfdiags.Diagnostics ) {
2536+ var diags tfdiags.Diagnostics
2537+
2538+ if cfgState == nil || locks == nil {
2539+ panic (fmt .Sprintf ("nil config or nil locks passed to GetStateStoreProviderFactory: config %#v, locks %#v" , cfgState , locks ))
2540+ }
2541+
2542+ if cfgState .Provider == nil || cfgState .Provider .Source .IsZero () {
2543+ // This should not happen; this data is populated when storing config state
2544+ return nil , diags .Append (& hcl.Diagnostic {
2545+ Severity : hcl .DiagError ,
2546+ Summary : "Unknown provider used for state storage" ,
2547+ Detail : "Terraform could not find the provider used with the state_store. This is a bug in Terraform and should be reported." ,
2548+ // Subject: &cfgState.TypeRange,
2549+ })
2550+ }
2551+
2552+ factories , err := m .ProviderFactoriesFromLocks (locks )
2553+ if err != nil {
2554+ // This may happen if the provider isn't present in the provider cache.
2555+ // This should be caught earlier by logic that diffs the config against the backend state file.
2556+ return nil , diags .Append (& hcl.Diagnostic {
2557+ Severity : hcl .DiagError ,
2558+ Summary : "Provider unavailable" ,
2559+ Detail : fmt .Sprintf ("Terraform experienced an error when trying to use provider %s (%q) to initialize the %q state store: %s" ,
2560+ cfgState .Type ,
2561+ cfgState .Provider .Source ,
2562+ cfgState .Type ,
2563+ err ),
2564+ // Subject: &cfgState.TypeRange,
2565+ })
2566+ }
2567+
2568+ factory , exists := factories [* cfgState .Provider .Source ]
2569+ if ! exists {
2570+ return nil , diags .Append (& hcl.Diagnostic {
2571+ Severity : hcl .DiagError ,
2572+ Summary : "Provider unavailable" ,
2573+ Detail : fmt .Sprintf ("The provider %s (%q) is required to initialize the %q state store, but the matching provider factory is missing. This is a bug in Terraform and should be reported." ,
2574+ cfgState .Type ,
2575+ cfgState .Provider .Source ,
2576+ cfgState .Type ,
2577+ ),
2578+ // Subject: &cfgState.TypeRange,
2579+ })
2580+ }
2581+
2582+ return factory , diags
2583+ }
2584+
25502585//-------------------------------------------------------------------
25512586// Output constants and initialization code
25522587//-------------------------------------------------------------------
0 commit comments