@@ -60,18 +60,9 @@ type BackendOpts struct {
6060 // the root module, or nil if no such block is present.
6161 StateStoreConfig * configs.StateStore
6262
63- // ProvidersFactory contains a factory for creating instances of the
64- // provider used for pluggable state storage. Each call created a new instance,
65- // so be conscious of when the provider needs to be configured, etc.
66- //
67- // This will only be set if the configuration contains a state_store block.
68- ProviderFactory providers.Factory
69-
7063 // Locks allows state-migration logic to detect when the provider used for pluggable state storage
7164 // during the last init (i.e. what's in the backend state file) is mismatched with the provider
7265 // version in use currently.
73- //
74- // This will only be set if the configuration contains a state_store block.
7566 Locks * depsfile.Locks
7667
7768 // ConfigOverride is an hcl.Body that, if non-nil, will be used with
@@ -577,16 +568,13 @@ func (m *Meta) stateStoreConfig(opts *BackendOpts) (*configs.StateStore, int, tf
577568 return nil , 0 , diags
578569 }
579570
580- // Check - is the state store type in the config supported by the provider?
581- if opts .ProviderFactory == nil {
582- diags = diags .Append (& hcl.Diagnostic {
583- Severity : hcl .DiagError ,
584- Summary : "Missing provider details when configuring state store" ,
585- 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." ,
586- })
571+ pFactory , pDiags := m .GetStateStoreProviderFactory (opts .StateStoreConfig , opts .Locks )
572+ diags = diags .Append (pDiags )
573+ if pDiags .HasErrors () {
587574 return nil , 0 , diags
588575 }
589- provider , err := opts .ProviderFactory ()
576+
577+ provider , err := pFactory ()
590578 if err != nil {
591579 diags = diags .Append (fmt .Errorf ("error when obtaining provider instance during state store initialization: %w" , err ))
592580 return nil , 0 , diags
@@ -941,7 +929,7 @@ func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Di
941929 // AND we're not providing any overrides. An override can mean a change overriding an unchanged backend block (indicated by the hash value).
942930 if (uint64 (cHash ) == s .StateStore .Hash ) && (! opts .Init || opts .ConfigOverride == nil ) {
943931 log .Printf ("[TRACE] Meta.Backend: using already-initialized, unchanged %q state_store configuration" , stateStoreConfig .Type )
944- savedStateStore , sssDiags := m .savedStateStore (sMgr , opts . ProviderFactory )
932+ savedStateStore , sssDiags := m .savedStateStore (sMgr )
945933 diags = diags .Append (sssDiags )
946934 // Verify that selected workspace exist. Otherwise prompt user to create one
947935 if opts .Init && savedStateStore != nil {
@@ -1587,43 +1575,37 @@ func (m *Meta) backend(configPath string, viewType arguments.ViewType) (backendr
15871575 return nil , diags
15881576 }
15891577
1578+ locks , lDiags := m .lockedDependencies ()
1579+ diags = diags .Append (lDiags )
1580+ if lDiags .HasErrors () {
1581+ return nil , diags
1582+ }
1583+
15901584 var opts * BackendOpts
15911585 switch {
15921586 case root .Backend != nil :
15931587 opts = & BackendOpts {
15941588 BackendConfig : root .Backend ,
1589+ Locks : locks ,
15951590 ViewType : viewType ,
15961591 }
15971592 case root .CloudConfig != nil :
15981593 backendConfig := root .CloudConfig .ToBackendConfig ()
15991594 opts = & BackendOpts {
16001595 BackendConfig : & backendConfig ,
1596+ Locks : locks ,
16011597 ViewType : viewType ,
16021598 }
16031599 case root .StateStore != nil :
1604- // In addition to config, use of a state_store requires
1605- // provider factory and provider locks data
1606- locks , lDiags := m .lockedDependencies ()
1607- diags = diags .Append (lDiags )
1608- if lDiags .HasErrors () {
1609- return nil , diags
1610- }
1611-
1612- factory , fDiags := m .GetStateStoreProviderFactory (root .StateStore , locks )
1613- diags = diags .Append (fDiags )
1614- if fDiags .HasErrors () {
1615- return nil , diags
1616- }
1617-
16181600 opts = & BackendOpts {
16191601 StateStoreConfig : root .StateStore ,
1620- ProviderFactory : factory ,
16211602 Locks : locks ,
16221603 ViewType : viewType ,
16231604 }
16241605 default :
16251606 // there is no config; defaults to local state storage
16261607 opts = & BackendOpts {
1608+ Locks : locks ,
16271609 ViewType : viewType ,
16281610 }
16291611 }
@@ -1702,7 +1684,7 @@ func (m *Meta) stateStore_C_s(c *configs.StateStore, stateStoreHash int, backend
17021684 }
17031685
17041686 // Get the state store as an instance of backend.Backend
1705- b , storeConfigVal , providerConfigVal , moreDiags := m .stateStoreInitFromConfig (c , opts .ProviderFactory )
1687+ b , storeConfigVal , providerConfigVal , moreDiags := m .stateStoreInitFromConfig (c , opts .Locks )
17061688 diags = diags .Append (moreDiags )
17071689 if diags .HasErrors () {
17081690 return nil , diags
@@ -1939,22 +1921,28 @@ func (m *Meta) createDefaultWorkspace(c *configs.StateStore, b backend.Backend)
19391921}
19401922
19411923// Initializing a saved state store from the backend state file (aka 'cache file', aka 'legacy state file')
1942- func (m * Meta ) savedStateStore (sMgr * clistate.LocalState , factory providers. Factory ) (backend.Backend , tfdiags.Diagnostics ) {
1924+ func (m * Meta ) savedStateStore (sMgr * clistate.LocalState ) (backend.Backend , tfdiags.Diagnostics ) {
19431925 // We're preparing a state_store version of backend.Backend.
19441926 //
19451927 // The provider and state store will be configured using the backend state file.
19461928
19471929 var diags tfdiags.Diagnostics
19481930 var b backend.Backend
19491931
1950- if factory == nil {
1951- diags = diags .Append (& hcl.Diagnostic {
1952- Severity : hcl .DiagError ,
1953- Summary : "Missing provider details when configuring state store" ,
1954- 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." ,
1955- })
1932+ s := sMgr .State ()
1933+
1934+ locks , lDiags := m .lockedDependencies ()
1935+ diags = diags .Append (lDiags )
1936+ if lDiags .HasErrors () {
19561937 return nil , diags
19571938 }
1939+
1940+ factory , pDiags := m .StateStoreProviderFactoryFromConfigState (s .StateStore , locks )
1941+ diags = diags .Append (pDiags )
1942+ if pDiags .HasErrors () {
1943+ return nil , diags
1944+ }
1945+
19581946 provider , err := factory ()
19591947 if err != nil {
19601948 diags = diags .Append (fmt .Errorf ("error when obtaining provider instance during state store initialization: %w" , err ))
@@ -1964,7 +1952,6 @@ func (m *Meta) savedStateStore(sMgr *clistate.LocalState, factory providers.Fact
19641952 // running provider instance inside the returned backend.Backend instance.
19651953 // Stopping the provider process is the responsibility of the calling code.
19661954
1967- s := sMgr .State ()
19681955 resp := provider .GetProviderSchema ()
19691956
19701957 if len (resp .StateStores ) == 0 {
@@ -2242,17 +2229,15 @@ func (m *Meta) backendInitFromConfig(c *configs.Backend) (backend.Backend, cty.V
22422229//
22432230// NOTE: the backend version of this method, `backendInitFromConfig`, prompts users for input if any required fields
22442231// are missing from the backend config. In `stateStoreInitFromConfig` we don't do this, and instead users will see an error.
2245- func (m * Meta ) stateStoreInitFromConfig (c * configs.StateStore , factory providers. Factory ) (backend.Backend , cty.Value , cty.Value , tfdiags.Diagnostics ) {
2232+ func (m * Meta ) stateStoreInitFromConfig (c * configs.StateStore , locks * depsfile. Locks ) (backend.Backend , cty.Value , cty.Value , tfdiags.Diagnostics ) {
22462233 var diags tfdiags.Diagnostics
22472234
2248- if factory == nil {
2249- diags = diags .Append (& hcl.Diagnostic {
2250- Severity : hcl .DiagError ,
2251- Summary : "Missing provider details when configuring state store" ,
2252- 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." ,
2253- })
2235+ factory , pDiags := m .GetStateStoreProviderFactory (c , locks )
2236+ diags = diags .Append (pDiags )
2237+ if pDiags .HasErrors () {
22542238 return nil , cty .NilVal , cty .NilVal , diags
22552239 }
2240+
22562241 provider , err := factory ()
22572242 if err != nil {
22582243 diags = diags .Append (fmt .Errorf ("error when obtaining provider instance during state store initialization: %w" , err ))
@@ -2533,6 +2518,56 @@ func (m *Meta) GetStateStoreProviderFactory(config *configs.StateStore, locks *d
25332518 return factory , diags
25342519}
25352520
2521+ func (m * Meta ) StateStoreProviderFactoryFromConfigState (cfgState * workdir.StateStoreConfigState , locks * depsfile.Locks ) (providers.Factory , tfdiags.Diagnostics ) {
2522+ var diags tfdiags.Diagnostics
2523+
2524+ if cfgState == nil || locks == nil {
2525+ panic (fmt .Sprintf ("nil config or nil locks passed to GetStateStoreProviderFactory: config %#v, locks %#v" , cfgState , locks ))
2526+ }
2527+
2528+ if cfgState .Provider == nil || cfgState .Provider .Source .IsZero () {
2529+ // This should not happen; this data is populated when storing config state
2530+ return nil , diags .Append (& hcl.Diagnostic {
2531+ Severity : hcl .DiagError ,
2532+ Summary : "Unknown provider used for state storage" ,
2533+ Detail : "Terraform could not find the provider used with the state_store. This is a bug in Terraform and should be reported." ,
2534+ // Subject: &cfgState.TypeRange,
2535+ })
2536+ }
2537+
2538+ factories , err := m .ProviderFactoriesFromLocks (locks )
2539+ if err != nil {
2540+ // This may happen if the provider isn't present in the provider cache.
2541+ // This should be caught earlier by logic that diffs the config against the backend state file.
2542+ return nil , diags .Append (& hcl.Diagnostic {
2543+ Severity : hcl .DiagError ,
2544+ Summary : "Provider unavailable" ,
2545+ Detail : fmt .Sprintf ("Terraform experienced an error when trying to use provider %s (%q) to initialize the %q state store: %s" ,
2546+ cfgState .Type ,
2547+ cfgState .Provider .Source ,
2548+ cfgState .Type ,
2549+ err ),
2550+ // Subject: &cfgState.TypeRange,
2551+ })
2552+ }
2553+
2554+ factory , exists := factories [* cfgState .Provider .Source ]
2555+ if ! exists {
2556+ return nil , diags .Append (& hcl.Diagnostic {
2557+ Severity : hcl .DiagError ,
2558+ Summary : "Provider unavailable" ,
2559+ 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." ,
2560+ cfgState .Type ,
2561+ cfgState .Provider .Source ,
2562+ cfgState .Type ,
2563+ ),
2564+ // Subject: &cfgState.TypeRange,
2565+ })
2566+ }
2567+
2568+ return factory , diags
2569+ }
2570+
25362571//-------------------------------------------------------------------
25372572// Output constants and initialization code
25382573//-------------------------------------------------------------------
0 commit comments