Skip to content

Commit 6e4e2a6

Browse files
SarahFrenchradeksimko
authored andcommitted
command/meta: Skip the GetProviderSchema cache on upgrade
1 parent ddd598e commit 6e4e2a6

File tree

7 files changed

+69
-36
lines changed

7 files changed

+69
-36
lines changed

internal/command/meta_backend.go

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ type BackendOpts struct {
6969
// during upgrade-triggered migrations.
7070
PreviousLocks *depsfile.Locks
7171

72+
SkipGetProviderSchemaCache bool
73+
7274
// ConfigOverride is an hcl.Body that, if non-nil, will be used with
7375
// configs.MergeBodies to override the type-specific backend configuration
7476
// arguments in Config.
@@ -374,7 +376,7 @@ func (m *Meta) BackendForLocalPlan(plan *plans.Plan) (backendrun.OperationsBacke
374376
return nil, diags
375377
}
376378

377-
factories, err := m.ProviderFactoriesFromLocks(locks)
379+
factories, err := m.ProviderFactoriesFromLocks(locks, false)
378380
if err != nil {
379381
// This may happen if the provider isn't present in the provider cache.
380382
// This should be caught earlier by logic that diffs the config against the backend state file.
@@ -1224,7 +1226,7 @@ func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Di
12241226
// AND we're not providing any overrides. An override can mean a change overriding an unchanged backend block (indicated by the hash value).
12251227
if (uint64(cHash) == s.StateStore.Hash) && (!opts.Init || opts.ConfigOverride == nil) {
12261228
log.Printf("[TRACE] Meta.Backend: using already-initialized, unchanged %q state_store configuration", stateStoreConfig.Type)
1227-
savedStateStore, sssDiags := m.savedStateStore(sMgr, opts.Locks)
1229+
savedStateStore, sssDiags := m.savedStateStore(sMgr, opts.Locks, false)
12281230
diags = diags.Append(sssDiags)
12291231
// Verify that selected workspace exist. Otherwise prompt user to create one
12301232
if opts.Init && savedStateStore != nil {
@@ -1242,7 +1244,7 @@ func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Di
12421244
// don't need to migrate, we update the state store cache hash value.
12431245
if !m.stateStoreConfigNeedsMigration(stateStoreConfig, s.StateStore, opts) {
12441246
log.Printf("[TRACE] Meta.Backend: using already-initialized %q state store configuration", stateStoreConfig.Type)
1245-
savedStateStore, moreDiags := m.savedStateStore(sMgr, opts.Locks)
1247+
savedStateStore, moreDiags := m.savedStateStore(sMgr, opts.Locks, false)
12461248
diags = diags.Append(moreDiags)
12471249
if moreDiags.HasErrors() {
12481250
return nil, diags
@@ -1309,6 +1311,20 @@ func (m *Meta) backendFromConfig(opts *BackendOpts) (backend.Backend, tfdiags.Di
13091311
return nil, diags
13101312
}
13111313

1314+
pLock := opts.Locks.Provider(stateStoreConfig.ProviderAddr)
1315+
lockVersion, err := providerreqs.GoVersionFromVersion(pLock.Version())
1316+
if err != nil {
1317+
diags = diags.Append(tfdiags.Sourceless(
1318+
tfdiags.Warning,
1319+
"Unable to determine version of the state store provider",
1320+
fmt.Sprintf("Failed to parse version of %s from the lock file: %s", stateStoreConfig.ProviderAddr.ForDisplay(), err),
1321+
))
1322+
return nil, diags
1323+
}
1324+
if !lockVersion.Equal(s.StateStore.Provider.Version) {
1325+
opts.SkipGetProviderSchemaCache = true
1326+
}
1327+
13121328
return m.stateStore_changed(stateStoreConfig, cHash, sMgr, opts, initReason)
13131329

13141330
default:
@@ -1497,7 +1513,7 @@ func (m *Meta) backendFromState(_ context.Context, locks *depsfile.Locks) (backe
14971513
// state_store
14981514
log.Printf("[TRACE] Meta.Backend: working directory was previously initialized for %q state store", s.StateStore.Type)
14991515
var ssDiags tfdiags.Diagnostics
1500-
b, ssDiags = m.savedStateStore(sMgr, locks) // Relies on the state manager's internal state being refreshed above.
1516+
b, ssDiags = m.savedStateStore(sMgr, locks, false) // Relies on the state manager's internal state being refreshed above.
15011517
diags = diags.Append(ssDiags)
15021518
if ssDiags.HasErrors() {
15031519
return nil, diags
@@ -2545,7 +2561,7 @@ func (m *Meta) stateStore_to_backend(ssSMgr *clistate.LocalState, dstBackendType
25452561
view.Output(views.StateMigrateLocalMessage, stateStoreType)
25462562

25472563
// Initialize the configured state store
2548-
ss, moreDiags := m.savedStateStore(ssSMgr, opts.Locks)
2564+
ss, moreDiags := m.savedStateStore(ssSMgr, opts.Locks, false)
25492565
diags = diags.Append(moreDiags)
25502566
if moreDiags.HasErrors() {
25512567
return nil, diags
@@ -2672,7 +2688,7 @@ func (m *Meta) stateStore_changed(cfg *configs.StateStore, cfgHash int, sMgr *cl
26722688
}
26732689

26742690
// Grab the source state store
2675-
srcB, srcBDiags := m.savedStateStore(sMgr, opts.PreviousLocks)
2691+
srcB, srcBDiags := m.savedStateStore(sMgr, opts.PreviousLocks, opts.SkipGetProviderSchemaCache)
26762692
diags = diags.Append(srcBDiags)
26772693
if srcBDiags.HasErrors() {
26782694
return nil, diags
@@ -2689,11 +2705,12 @@ func (m *Meta) stateStore_changed(cfg *configs.StateStore, cfgHash int, sMgr *cl
26892705

26902706
// Perform the migration
26912707
err := m.backendMigrateState(&backendMigrateOpts{
2692-
SourceType: s.StateStore.Type,
2693-
DestinationType: cfg.Type,
2694-
Source: srcB,
2695-
Destination: dstB,
2696-
ViewType: vt,
2708+
SkipGetProviderSchemaCache: opts.SkipGetProviderSchemaCache,
2709+
SourceType: s.StateStore.Type,
2710+
DestinationType: cfg.Type,
2711+
Source: srcB,
2712+
Destination: dstB,
2713+
ViewType: vt,
26972714
})
26982715
if err != nil {
26992716
diags = diags.Append(err)
@@ -2826,7 +2843,7 @@ To make the initial dependency selections that will initialize the dependency lo
28262843
}
28272844

28282845
// Initializing a saved state store from the backend state file (aka 'cache file', aka 'legacy state file')
2829-
func (m *Meta) savedStateStore(sMgr *clistate.LocalState, locks *depsfile.Locks) (backend.Backend, tfdiags.Diagnostics) {
2846+
func (m *Meta) savedStateStore(sMgr *clistate.LocalState, locks *depsfile.Locks, skipCache bool) (backend.Backend, tfdiags.Diagnostics) {
28302847
// We're preparing a state_store version of backend.Backend.
28312848
//
28322849
// The provider and state store will be configured using the backend state file.
@@ -2835,7 +2852,7 @@ func (m *Meta) savedStateStore(sMgr *clistate.LocalState, locks *depsfile.Locks)
28352852

28362853
s := sMgr.State()
28372854

2838-
factory, pDiags := m.StateStoreProviderFactoryFromConfigState(s.StateStore, locks)
2855+
factory, pDiags := m.StateStoreProviderFactoryFromConfigState(s.StateStore, locks, skipCache)
28392856
diags = diags.Append(pDiags)
28402857
if pDiags.HasErrors() {
28412858
return nil, diags
@@ -3317,7 +3334,7 @@ func (m *Meta) StateStoreProviderFactoryFromConfig(config *configs.StateStore, l
33173334
})
33183335
}
33193336

3320-
factories, err := m.ProviderFactoriesFromLocks(locks)
3337+
factories, err := m.ProviderFactoriesFromLocks(locks, false)
33213338
if err != nil {
33223339
// This may happen if the provider isn't present in the provider cache.
33233340
// This should be caught earlier by logic that diffs the config against the backend state file.
@@ -3350,7 +3367,7 @@ func (m *Meta) StateStoreProviderFactoryFromConfig(config *configs.StateStore, l
33503367
return factory, diags
33513368
}
33523369

3353-
func (m *Meta) StateStoreProviderFactoryFromConfigState(cfgState *workdir.StateStoreConfigState, locks *depsfile.Locks) (providers.Factory, tfdiags.Diagnostics) {
3370+
func (m *Meta) StateStoreProviderFactoryFromConfigState(cfgState *workdir.StateStoreConfigState, locks *depsfile.Locks, skipCache bool) (providers.Factory, tfdiags.Diagnostics) {
33543371
var diags tfdiags.Diagnostics
33553372

33563373
if cfgState == nil {
@@ -3366,7 +3383,7 @@ func (m *Meta) StateStoreProviderFactoryFromConfigState(cfgState *workdir.StateS
33663383
})
33673384
}
33683385

3369-
factories, err := m.providerFactoriesFromLocks(locks)
3386+
factories, err := m.providerFactoriesFromLocks(locks, skipCache)
33703387
if err != nil {
33713388
// This may happen if the provider isn't present in the provider cache.
33723389
// This should be caught earlier by logic that diffs the config against the backend state file.

internal/command/meta_backend_migrate.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828

2929
type backendMigrateOpts struct {
3030
SourceType, DestinationType string
31+
SkipGetProviderSchemaCache bool
3132
Source, Destination backend.Backend
3233
ViewType arguments.ViewType
3334

@@ -496,7 +497,8 @@ func (m *Meta) backendMigrateEmptyConfirm(source, destination statemgr.Full, opt
496497
}
497498

498499
func (m *Meta) backendMigrateNonEmptyConfirm(
499-
sourceState, destinationState statemgr.Full, opts *backendMigrateOpts) (bool, error) {
500+
sourceState, destinationState statemgr.Full, opts *backendMigrateOpts,
501+
) (bool, error) {
500502
// We need to grab both states so we can write them to a file
501503
source := sourceState.State()
502504
destination := destinationState.State()
@@ -580,7 +582,7 @@ func (m *Meta) backendMigrateTFC(opts *backendMigrateOpts) error {
580582
if err != nil {
581583
return err
582584
}
583-
//to be used below, not yet implamented
585+
// to be used below, not yet implamented
584586
// destinationWorkspaces, destinationSingleState
585587
_, _, err = retrieveWorkspaces(opts.Destination, opts.SourceType)
586588
if err != nil {
@@ -639,7 +641,7 @@ func (m *Meta) backendMigrateTFC(opts *backendMigrateOpts) error {
639641
if migrate, err := m.promptSingleToCloudSingleStateMigration(opts); err != nil {
640642
return err
641643
} else if !migrate {
642-
return nil //skip migrating but return successfully
644+
return nil // skip migrating but return successfully
643645
}
644646

645647
return m.backendMigrateState_s_s(opts)

internal/command/meta_backend_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2430,7 +2430,7 @@ func TestSavedStateStore(t *testing.T) {
24302430
}
24312431

24322432
// Code under test
2433-
b, diags := m.savedStateStore(sMgr, locks)
2433+
b, diags := m.savedStateStore(sMgr, locks, false)
24342434
if diags.HasErrors() {
24352435
t.Fatalf("unexpected errors: %s", diags.Err())
24362436
}
@@ -2474,7 +2474,7 @@ func TestSavedStateStore(t *testing.T) {
24742474
t.Fatal(dDiags.Err())
24752475
}
24762476

2477-
_, diags := m.savedStateStore(sMgr, locks)
2477+
_, diags := m.savedStateStore(sMgr, locks, false)
24782478
if !diags.HasErrors() {
24792479
t.Fatal("expected errors but got none")
24802480
}
@@ -2516,7 +2516,7 @@ func TestSavedStateStore(t *testing.T) {
25162516
t.Fatal(dDiags.Err())
25172517
}
25182518

2519-
_, diags := m.savedStateStore(sMgr, locks)
2519+
_, diags := m.savedStateStore(sMgr, locks, false)
25202520
if !diags.HasErrors() {
25212521
t.Fatal("expected errors but got none")
25222522
}

internal/command/meta_providers.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,9 @@ func (m *Meta) ProviderFactories() (map[addrs.Provider]providers.Factory, error)
280280
return nil, fmt.Errorf("failed to read dependency lock file: %s", diags.Err())
281281
}
282282

283-
return m.providerFactoriesFromLocks(locks)
283+
// Pass false as skipCache because this function is not used to launch 'old' versions of a provider
284+
// during a state migration using state_store
285+
return m.providerFactoriesFromLocks(locks, false)
284286
}
285287

286288
// ProviderFactoriesFromLocks receives in memory locks and uses them to produce a map
@@ -290,12 +292,12 @@ func (m *Meta) ProviderFactories() (map[addrs.Provider]providers.Factory, error)
290292
// ProviderFactoriesFromLocks should only be used if the calling code relies on locks
291293
// that have not yet been persisted to a dependency lock file on disk. Realistically, this
292294
// means only code in the init command should use this method.
293-
func (m *Meta) ProviderFactoriesFromLocks(configLocks *depsfile.Locks) (map[addrs.Provider]providers.Factory, error) {
295+
func (m *Meta) ProviderFactoriesFromLocks(configLocks *depsfile.Locks, skipCache bool) (map[addrs.Provider]providers.Factory, error) {
294296
// Ensure overrides and unmanaged providers are reflected in the returned list of factories,
295297
// while avoiding mutating the in-memory
296298
locks := m.annotateDependencyLocksWithOverrides(configLocks.DeepCopy())
297299

298-
return m.providerFactoriesFromLocks(locks)
300+
return m.providerFactoriesFromLocks(locks, skipCache)
299301
}
300302

301303
// providerFactoriesFromLocks returns a map of provider factories from a given set of locks.
@@ -304,7 +306,7 @@ func (m *Meta) ProviderFactoriesFromLocks(configLocks *depsfile.Locks) (map[addr
304306
// Instead, use:
305307
// * `ProviderFactoriesFromLocks` - for use when locks aren't yet persisted to a dependency lock file.
306308
// * `ProviderFactories` - for use when Terraform is guaranteed to read all necessary locks from a dependency lock file.
307-
func (m *Meta) providerFactoriesFromLocks(locks *depsfile.Locks) (map[addrs.Provider]providers.Factory, error) {
309+
func (m *Meta) providerFactoriesFromLocks(locks *depsfile.Locks, skipCache bool) (map[addrs.Provider]providers.Factory, error) {
308310
// We'll always run through all of our providers, even if one of them
309311
// encounters an error, so that we can potentially report multiple errors
310312
// where appropriate and so that callers can potentially make use of the
@@ -390,7 +392,7 @@ func (m *Meta) providerFactoriesFromLocks(locks *depsfile.Locks) (map[addrs.Prov
390392
continue
391393
}
392394
}
393-
factories[provider] = providerFactory(cached)
395+
factories[provider] = providerFactory(cached, skipCache)
394396
}
395397
for provider, localDir := range devOverrideProviders {
396398
factories[provider] = devOverrideProviderFactory(provider, localDir)
@@ -419,7 +421,7 @@ func (m *Meta) internalProviders() map[string]providers.Factory {
419421
// providerFactory produces a provider factory that runs up the executable
420422
// file in the given cache package and uses go-plugin to implement
421423
// providers.Interface against it.
422-
func providerFactory(meta *providercache.CachedProvider) providers.Factory {
424+
func providerFactory(meta *providercache.CachedProvider, skipCache bool) providers.Factory {
423425
return func() (providers.Interface, error) {
424426
execFile, err := meta.ExecutableFile()
425427
if err != nil {
@@ -451,23 +453,25 @@ func providerFactory(meta *providercache.CachedProvider) providers.Factory {
451453

452454
// store the client so that the plugin can kill the child process
453455
protoVer := client.NegotiatedVersion()
454-
return finalizeFactoryPlugin(raw, protoVer, meta.Provider, client), nil
456+
return finalizeFactoryPlugin(raw, protoVer, meta.Provider, skipCache, client), nil
455457
}
456458
}
457459

458460
// finalizeFactoryPlugin completes the setup of a plugin dispensed by the rpc
459461
// client to be returned by the plugin factory.
460-
func finalizeFactoryPlugin(rawPlugin any, protoVersion int, addr addrs.Provider, client *plugin.Client) providers.Interface {
462+
func finalizeFactoryPlugin(rawPlugin any, protoVersion int, addr addrs.Provider, skipCache bool, client *plugin.Client) providers.Interface {
461463
switch protoVersion {
462464
case 5:
463465
p := rawPlugin.(*tfplugin.GRPCProvider)
464466
p.PluginClient = client
465467
p.Addr = addr
468+
p.SkipCache = skipCache
466469
return p
467470
case 6:
468471
p := rawPlugin.(*tfplugin6.GRPCProvider)
469472
p.PluginClient = client
470473
p.Addr = addr
474+
p.SkipCache = skipCache
471475
return p
472476
default:
473477
panic("unsupported protocol version")
@@ -480,11 +484,12 @@ func devOverrideProviderFactory(provider addrs.Provider, localDir getproviders.P
480484
// doesn't actually care about the version, so we can leave it
481485
// unspecified: overridden providers are not explicitly versioned.
482486
log.Printf("[DEBUG] Provider %s is overridden to load from %s", provider, localDir)
487+
skipCache := false
483488
return providerFactory(&providercache.CachedProvider{
484489
Provider: provider,
485490
Version: getproviders.UnspecifiedVersion,
486491
PackageDir: string(localDir),
487-
})
492+
}, skipCache)
488493
}
489494

490495
// unmanagedProviderFactory produces a provider factory that uses the passed
@@ -532,16 +537,17 @@ func unmanagedProviderFactory(provider addrs.Provider, reattach *plugin.Reattach
532537

533538
// store the client so that the plugin can kill the child process
534539
protoVer := client.NegotiatedVersion()
540+
skipCache := false
535541
switch protoVer {
536542
case 0, 5:
537543
// As of the 0.15 release, sdk.v2 doesn't include the protocol
538544
// version in the ReattachConfig (only recently added to
539545
// go-plugin), so client.NegotiatedVersion() always returns 0. We
540546
// assume that an unmanaged provider reporting protocol version 0 is
541547
// actually using proto v5 for backwards compatibility.
542-
return finalizeFactoryPlugin(raw, 5, provider, client), nil
548+
return finalizeFactoryPlugin(raw, 5, provider, skipCache, client), nil
543549
case 6:
544-
return finalizeFactoryPlugin(raw, 6, provider, client), nil
550+
return finalizeFactoryPlugin(raw, 6, provider, skipCache, client), nil
545551
default:
546552
return nil, fmt.Errorf("unsupported protocol version %d", protoVer)
547553
}

internal/plugin/grpc_provider.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ type GRPCProvider struct {
6464
// but it may not always be available for alternative execute modes.
6565
Addr addrs.Provider
6666

67+
// SkipCache WIP
68+
SkipCache bool
69+
6770
// Proto client use to make the grpc service calls.
6871
client proto.ProviderClient
6972

@@ -83,7 +86,7 @@ func (p *GRPCProvider) GetProviderSchema() providers.GetProviderSchemaResponse {
8386
defer p.mu.Unlock()
8487

8588
// check the global cache if we can
86-
if !p.Addr.IsZero() {
89+
if !p.Addr.IsZero() && !p.SkipCache {
8790
if resp, ok := providers.SchemaCache.Get(p.Addr); ok && resp.ServerCapabilities.GetProviderSchemaOptional {
8891
logger.Trace("GRPCProvider: returning cached schema", p.Addr.String())
8992
return resp

internal/plugin6/grpc_provider.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ type GRPCProvider struct {
7171
// but it may not always be available for alternative execute modes.
7272
Addr addrs.Provider
7373

74+
// SkipCache WIP
75+
SkipCache bool
76+
7477
// Proto client use to make the grpc service calls.
7578
client proto6.ProviderClient
7679

@@ -93,7 +96,7 @@ func (p *GRPCProvider) GetProviderSchema() providers.GetProviderSchemaResponse {
9396
defer p.mu.Unlock()
9497

9598
// check the global cache if we can
96-
if !p.Addr.IsZero() {
99+
if !p.Addr.IsZero() && !p.SkipCache {
97100
if resp, ok := providers.SchemaCache.Get(p.Addr); ok && resp.ServerCapabilities.GetProviderSchemaOptional {
98101
logger.Trace("GRPCProvider.v6: returning cached schema", p.Addr.String())
99102
return resp
@@ -208,7 +211,7 @@ func (p *GRPCProvider) GetProviderSchema() providers.GetProviderSchemaResponse {
208211
}
209212

210213
// set the global cache if we can
211-
if !p.Addr.IsZero() {
214+
if !p.Addr.IsZero() && !p.SkipCache {
212215
providers.SchemaCache.Set(p.Addr, resp)
213216
}
214217

internal/rpcapi/dependencies.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,11 +717,13 @@ func providerFactoriesForLocks(locks *depsfile.Locks, pluginsDir *providercache.
717717
p := raw.(*tfplugin.GRPCProvider)
718718
p.PluginClient = client
719719
p.Addr = addr
720+
p.SkipCache = false
720721
return p, nil
721722
case 6:
722723
p := raw.(*tfplugin6.GRPCProvider)
723724
p.PluginClient = client
724725
p.Addr = addr
726+
p.SkipCache = false
725727
return p, nil
726728
default:
727729
panic("unsupported protocol version")

0 commit comments

Comments
 (0)