This change makes some reversion of changes to the init command created during the PSS project, in order to support the Policy feature. Also see this change, which altered the provider download logic: https://github.com/hashicorp/terraform/pull/38648
Broadly this change's goal is to make module download happen after the backend is initialised. This was how init was structured in the past, and for a while in v1.15 of Terraform this step was moved to before backend initialisation, as the first provider download step downloaded all providers in the config (so loading the entire config was needed at that point in init).
The changes make this code go back to resembling the old order of events in init prior to v1.15. See this for reference: https://github.com/hashicorp/terraform/blob/v1.14.9/internal/command/init_run.go
To facilitate this change some code needed to be updated to use a config.Module as input, which is obtained by parsing the root module only. Previously once the whole configuration was parsed, after module download, that code was being passed an entire config.Config variable.
There are also some small refactoring and improvements, e.g. removing the `header` boolean from the init command implementation, as it had become redundant over time.
body: 'command/init:Provider installation was changed to enable future enhancements in the area. This partially reverses the init event order changes from v1.15; module installation will now occur after the backend is initialized. The change should not have any significant end-user impact aside from the command output.'
// The provider was not processed in the FetchPackageBegin callback.
// A provider that wasn't downloaded during this init could be because:
// * It was already present from a previous installation.
// * If upgrading, no newer version was available that matched version constraints.
// * Or, the provider is unmanaged/reattached and so download was skipped.
log.Printf("[TRACE] init (getProvidersFromPSSConfig): the state storage provider %s (%q) will not be changed in the dependency lock file after provider installation. Either it was already present and/or there was no available upgrade version that matched version constraints.",config.Module.StateStore.ProviderAddr.Type,config.Module.StateStore.ProviderAddr)
log.Printf("[TRACE] init (getProvidersFromPSSConfig): the state storage provider %s (%q) will not be changed in the dependency lock file after provider installation. Either it was already present and/or there was no available upgrade version that matched version constraints.",rootModEarly.StateStore.ProviderAddr.Type,rootModEarly.StateStore.ProviderAddr)
safeInitAction=SafeInitActionProceed
}else{
// The provider was processed in the FetchPackageBegin callback, so either it's being downloaded for the first time, or upgraded.
log.Printf("[TRACE] init (getProvidersFromConfig): the state storage provider %s (%q) will be changed in the dependency lock file during provider installation.",config.Module.StateStore.ProviderAddr.Type,config.Module.StateStore.ProviderAddr)
log.Printf("[TRACE] init (getProvidersFromConfig): the state storage provider %s (%q) will be changed in the dependency lock file during provider installation.",rootModEarly.StateStore.ProviderAddr.Type,rootModEarly.StateStore.ProviderAddr)
// If the provider is downloaded from a local source we assume it's safe.
// We don't require presence of the -safe-init flag, or require input from the user to approve its usage.
log.Printf("[TRACE] init (getProvidersFromConfig): the state storage provider %s (%q) is downloaded from a local source, so we consider it safe.",config.Module.StateStore.ProviderAddr.Type,config.Module.StateStore.ProviderAddr)
log.Printf("[TRACE] init (getProvidersFromConfig): the state storage provider %s (%q) is downloaded from a local source, so we consider it safe.",rootModEarly.StateStore.ProviderAddr.Type,rootModEarly.StateStore.ProviderAddr)
safeInitAction=SafeInitActionProceed
casegetproviders.PackageHTTPURL:
log.Printf("[DEBUG] init (getProvidersFromConfig): the state storage provider %s (%q) is downloaded via HTTP, so we consider it potentially unsafe.",config.Module.StateStore.ProviderAddr.Type,config.Module.StateStore.ProviderAddr)
log.Printf("[DEBUG] init (getProvidersFromConfig): the state storage provider %s (%q) is downloaded via HTTP, so we consider it potentially unsafe.",rootModEarly.StateStore.ProviderAddr.Type,rootModEarly.StateStore.ProviderAddr)
safeInitAction=SafeInitActionRequireApproval
default:
panic(fmt.Sprintf("init (getProvidersFromConfig): unexpected provider location type for state storage provider %q: %T",config.Module.StateStore.ProviderAddr,location))
panic(fmt.Sprintf("init (getProvidersFromConfig): unexpected provider location type for state storage provider %q: %T",rootModEarly.StateStore.ProviderAddr,location))
// Now the full configuration is loaded, we can download the providers specified in the configuration.
// This is step one of a two-step provider download process
// Providers may be downloaded by this code, but the dependency lock file is only updated later in `init`
// after step two of provider download is complete.
previousLocks,moreDiags:=c.lockedDependencies()
diags=diags.Append(moreDiags)
// If -state-provider-lock-file is set, we'll use that to obtain a new lock used for the state store provider
// This will be 'upserted': it may be that the previous locks don't contain the provider being added. potentially due to being empty, or contain a different version.
// The lock added will be used in the first step of provider download.
//
// We leave `previousLocks` unchanged so it can be used to accurately detect changes to the locks when the lock file is updated later.
// We load locks from any pre-existing dependency lock file. These may or may not be altered by the -state-provider-lock-file flag.
// The altered copy of the locks will be used to influence subsequent provider download steps.
// The unaltered copy of the locks will be used at the end of the run to determine whether we need to update the dependency lock file on disk.
"State store provider not found in -state-provider-lock-file dependency lock file",
fmt.Sprintf("Terraform could not find the state store provider %q (%s) in the dependency lock file %q provided via the -state-provider-lock-file flag. Please ensure the lock file contains a lock for the state store provider and try again.",
@ -321,7 +267,7 @@ Please use \"terraform state migrate -upgrade\" to upgrade the state store provi
}else{
// Confirm that a lock was used to control download.
// Note: we have to wait and do that here because at this point we know the provider was downloaded from a source that requires additional info about trust.
// No lock was provided for the state store provider either through pre-existing locks or through the -state-provider-lock-file flag.
diags=diags.Append(tfdiags.Sourceless(
tfdiags.Error,
@ -337,12 +283,12 @@ Please use \"terraform state migrate -upgrade\" to upgrade the state store provi
// Handle SafeInitActionInvalid or unexpected action types
panic(fmt.Sprintf("When installing providers described in the config Terraform couldn't determine what 'safe init' action should be taken and returned action type %T. This is a bug in Terraform and should be reported.",safeInitAction))
}
}
// If we outputted information, then we need to output a newline
// so that our success message is nicely spaced out from prior text.
ifheader{
view.Output(views.EmptyMessage)
// Record how the state store provider is supplied to Terraform
{"@level":"info","@message":"Initializing the backend...","@module":"terraform.ui","message_code": "initializing_backend_message","type":"init_output"}
{"@level":"info","@message":"- foo in foo","@module":"terraform.ui","type":"log"}
{"@level":"info","@message":"Initializing the backend...","@module":"terraform.ui","message_code": "initializing_backend_message","type":"init_output"}
{"@level":"info","@message":"Terraform has been successfully initialized!","@module":"terraform.ui","message_code": "output_init_success_message","type":"init_output"}
{"@level":"info","@message":"You may now begin working with Terraform. Try running \"terraform plan\" to see\nany changes that are required for your infrastructure. All Terraform commands\nshould now work.\n\nIf you ever set or change modules or backend configuration for Terraform,\nrerun this command to reinitialize your working directory. If you forget, other\ncommands will detect it and remind you to do so if necessary.","@module":"terraform.ui","message_code": "output_init_success_cli_message","type":"init_output"}