fix: Simplify how we block upgrading the PSS provider during `init -upgrade`, now that one download step is specific to the PSS provider. (#38690)

In #38648 the provider download process was changed:

Previously the two steps were:
1. Download providers based on configuration
2. Download providers based on state

The process remains two steps but the new steps are:
1. Download 0-1 provider if one is needed for PSS (1 provider downloaded if PSS is in use)
2. Download all other providers (configuration + state providers)

Because the first download step is specific to the provider used for state storage we can specifically block that provider being upgraded during init. We block upgrade unless the -reconfigure flag is supplied (i.e. the user isn't wanting to migrate state). Users see a warning when they perform an upgrade action and PSS is in use.

Prior to this, users would get an error if the upgrade process impacted the state store provider, now it's never impacts and warnings remind users to upgrade that provider via another command.
main
Sarah French 14 hours ago committed by GitHub
parent ff406ab69b
commit 7d5baea55e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -277,7 +277,29 @@ func (c *InitCommand) run(initArgs *arguments.Init, view views.Init) int {
var stateStoreProviderAuthResult *getproviders.PackageAuthenticationResult
var configProviderDiags tfdiags.Diagnostics
configProvidersOutput, pssLocks, safeInitAction, stateStoreProviderAuthResult, configProviderDiags = c.getProvidersFromPSSConfig(ctx, config, alteredPreviousLocks, initArgs.Upgrade, initArgs.PluginPath, initArgs.Lockfile, view)
// The init command is not allowed to upgrade the provider used for state storage
// We warn that upgrades will not impact the provider, and upgrades will only work via `terraform state migrate -upgrade`.
var allowUpgrade bool
if initArgs.Upgrade {
if initArgs.Reconfigure {
allowUpgrade = true // user is opting out of migrating state; whatever happens, happens
} else {
allowUpgrade = false // the installer will only be able to reuse the old version.
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Warning,
"Cannot upgrade the provider used for state storage during \"terraform init -upgrade\"",
fmt.Sprintf(`Terraform will not upgrade the %s (%q) provider as part of this operation because it is used for state storage.
Please use \"terraform state migrate -upgrade\" to upgrade the state store provider and navigate migrating your state between the two versions.`,
config.Module.StateStore.ProviderAddr.Type,
config.Module.StateStore.ProviderAddr.ForDisplay(),
),
),
)
}
}
configProvidersOutput, pssLocks, safeInitAction, stateStoreProviderAuthResult, configProviderDiags = c.getProvidersFromPSSConfig(ctx, config, alteredPreviousLocks, allowUpgrade, initArgs.PluginPath, initArgs.Lockfile, view)
diags = diags.Append(configProviderDiags)
if configProviderDiags.HasErrors() {
view.Diagnostics(diags)
@ -322,41 +344,6 @@ func (c *InitCommand) run(initArgs *arguments.Init, view views.Init) int {
}
}
// The init command is not allowed to upgrade the provider used for state storage (unless we're reconfiguring the state store).
// Unless users choose to reconfigure, they must upgrade the state store provider separately using `terraform state migrate -upgrade`.
// We only check to see if the state store provider was upgraded if the provider supply mode is ManagedByTerraform; providers overridden
// using dev_override or unmanaged providers blocks any upgrade process impacting that provider.
// For more context, see: https://github.com/hashicorp/terraform/pull/38633
if initArgs.Upgrade &&
!initArgs.Reconfigure &&
config.Module.StateStore != nil &&
config.Module.StateStore.ProviderSupplyMode == getproviders.ManagedByTerraform {
pAddr := config.Module.StateStore.ProviderAddr
old := alteredPreviousLocks.Provider(pAddr)
new := pssLocks.Provider(pAddr)
if old == nil || new == nil {
panic(fmt.Sprintf(`Unexpected missing provider lock for %s during init -upgrade:
prior lock: %#v
new lock: %#v`, pAddr.ForDisplay(), old, new))
}
if !new.Version().Same((old.Version())) {
// The upgrade has impacted the provider
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Cannot upgrade the provider used for state storage during \"terraform init -upgrade\"",
fmt.Sprintf(`While upgrading providers Terraform attempted to upgrade the %s (%q) provider, which is used by the state_store block in your configuration.
Please use \"terraform state migrate -upgrade\" to upgrade the state store provider and navigate migrating your state between the two versions. You can then re-attempt \"terraform init -upgrade\" to upgrade the rest of your providers.
If you do not intend to upgrade the state store provider, please update your configuration to pin to the current version (%s), and re-run \"terraform init -upgrade\" to upgrade the rest of your providers.
`,
pAddr.Type, pAddr.ForDisplay(), old.Version()),
),
)
view.Diagnostics(diags)
return 1
}
}
// If we outputted information, then we need to output a newline
// so that our success message is nicely spaced out from prior text.
if header {

@ -2593,13 +2593,13 @@ terraform {
"-enable-pluggable-state-storage-experiment",
}
code := c.Run(args)
if code == 0 {
t.Fatalf("command was not expected to complete successfully, but it did:\n%s", done(t).All())
if code != 0 {
t.Fatalf("command was expected to complete successfully, but it did not:\n%s", done(t).All())
}
output := done(t).Stderr()
expectedError := "Error: Cannot upgrade the provider used for state storage during \"terraform init -upgrade\""
if !strings.Contains(output, expectedError) {
t.Fatalf("expected error message not found:\n%s", output)
output := done(t).Stdout()
expectedMsg := "Warning: Cannot upgrade the provider used for state storage during \"terraform init -upgrade\""
if !strings.Contains(output, expectedMsg) {
t.Fatalf("expected warning message not found:\n%s", output)
}
// Assert that no providers were upgraded.

Loading…
Cancel
Save