@ -8,6 +8,7 @@ import (
"fmt"
"log"
"reflect"
"slices"
"sort"
"strings"
@ -434,7 +435,6 @@ func (c *InitCommand) getProviders(ctx context.Context, config *configs.Config,
) ,
) )
}
} ,
QueryPackagesWarning : func ( provider addrs . Provider , warnings [ ] string ) {
displayWarnings := make ( [ ] string , len ( warnings ) )
@ -694,7 +694,16 @@ func (c *InitCommand) getProviders(ctx context.Context, config *configs.Config,
// The method downloads any missing providers that aren't already downloaded and then returns
// dependency lock data based on the configuration.
// The dependency lock file itself isn't updated here.
func ( c * InitCommand ) getProvidersFromConfig ( ctx context . Context , config * configs . Config , upgrade bool , pluginDirs [ ] string , flagLockfile string , view views . Init ) ( output bool , resultingLocks * depsfile . Locks , diags tfdiags . Diagnostics ) {
func ( c * InitCommand ) getProvidersFromConfig (
ctx context . Context ,
config * configs . Config ,
upgrade bool ,
pluginDirs arguments . FlagStringSlice , // Not needed for PSS stuff - for installer sources.
flagLockfile string ,
backendInit bool ,
safeInit bool ,
view views . Init ,
) ( output bool , resultingLocks * depsfile . Locks , diags tfdiags . Diagnostics ) {
ctx , span := tracer . Start ( ctx , "install providers from config" )
defer span . End ( )
@ -746,7 +755,16 @@ func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *config
log . Printf ( "[DEBUG] will search for provider plugins in %s" , pluginDirs )
}
evts := c . prepareInstallerEvents ( ctx , reqs , diags , inst , view , views . InitializingProviderPluginFromConfigMessage , views . ReusingPreviousVersionInfo )
// TODO:
// if backendInit = false then either we're using a previously installed provider for state storage,
// or the config is being ignored and an implied local backend will be used instead.
// Think about use of backendInit here and edge cases.
safeOpts := & safeInitOptions { }
if config . Module . StateStore != nil {
safeOpts . providers = [ ] addrs . Provider { config . Module . StateStore . ProviderAddr }
safeOpts . safeInitEnabled = safeInit
}
evts := c . prepareInstallerEvents ( ctx , reqs , diags , inst , safeOpts , view , views . InitializingProviderPluginFromConfigMessage , views . ReusingPreviousVersionInfo )
ctx = evts . OnContext ( ctx )
mode := providercache . InstallNewProvidersOnly
@ -795,7 +813,7 @@ func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *config
// The calling code is assumed to have already called getProvidersFromConfig, which is used to
// supply the configLocks argument.
// The dependency lock file itself isn't updated here.
func ( c * InitCommand ) getProvidersFromState ( ctx context . Context , state * states . State , configLocks * depsfile . Locks , upgrade bool , pluginDirs [ ] string , flagLockfile string , view views . Init ) ( output bool , resultingLocks * depsfile . Locks , diags tfdiags . Diagnostics ) {
func ( c * InitCommand ) getProvidersFromState ( ctx context . Context , state * states . State , configLocks * depsfile . Locks , upgrade bool , pluginDirs [ ] string , flagLockfile string , safeInit bool , view views . Init ) ( output bool , resultingLocks * depsfile . Locks , diags tfdiags . Diagnostics ) {
ctx , span := tracer . Start ( ctx , "install providers from state" )
defer span . End ( )
@ -863,7 +881,8 @@ func (c *InitCommand) getProvidersFromState(ctx context.Context, state *states.S
// things relatively concise. Later it'd be nice to have a progress UI
// where statuses update in-place, but we can't do that as long as we
// are shimming our vt100 output to the legacy console API on Windows.
evts := c . prepareInstallerEvents ( ctx , reqs , diags , inst , view , views . InitializingProviderPluginFromStateMessage , views . ReusingVersionIdentifiedFromConfig )
var safeOpts * safeInitOptions
evts := c . prepareInstallerEvents ( ctx , reqs , diags , inst , safeOpts , view , views . InitializingProviderPluginFromStateMessage , views . ReusingVersionIdentifiedFromConfig )
ctx = evts . OnContext ( ctx )
mode := providercache . InstallNewProvidersOnly
@ -898,7 +917,6 @@ func (c *InitCommand) getProvidersFromState(ctx context.Context, state *states.S
// The calling code is expected to provide the previous locks (if any) and the two sets of locks determined from
// configuration and state data.
func ( c * InitCommand ) saveDependencyLockFile ( previousLocks , configLocks , stateLocks * depsfile . Locks , flagLockfile string , view views . Init ) ( output bool , diags tfdiags . Diagnostics ) {
// Get the combination of config and state locks
newLocks := c . mergeLockedDependencies ( configLocks , stateLocks )
@ -964,11 +982,16 @@ func (c *InitCommand) saveDependencyLockFile(previousLocks, configLocks, stateLo
return output , diags
}
// safeInitOptions
type safeInitOptions struct {
providers [ ] addrs . Provider
safeInitEnabled bool
}
// prepareInstallerEvents returns an instance of *providercache.InstallerEvents. This struct defines callback functions that will be executed
// when a specific type of event occurs during provider installation.
// The calling code needs to provide a tfdiags.Diagnostics collection, so that provider installation code returns diags to the calling code using closures
func ( c * InitCommand ) prepareInstallerEvents ( ctx context . Context , reqs providerreqs . Requirements , diags tfdiags . Diagnostics , inst * providercache . Installer , view views . Init , initMsg views . InitMessageCode , reuseMsg views . InitMessageCode ) * providercache . InstallerEvents {
func ( c * InitCommand ) prepareInstallerEvents ( ctx context . Context , reqs providerreqs . Requirements , diags tfdiags . Diagnostics , inst * providercache . Installer , safeOpts * safeInitOptions , view views . Init , initMsg views . InitMessageCode , reuseMsg views . InitMessageCode ) * providercache . InstallerEvents {
// Because we're currently just streaming a series of events sequentially
// into the terminal, we're showing only a subset of the events to keep
// things relatively concise. Later it'd be nice to have a progress UI
@ -1007,6 +1030,37 @@ func (c *InitCommand) prepareInstallerEvents(ctx context.Context, reqs providerr
} ,
FetchPackageBegin : func ( provider addrs . Provider , version getproviders . Version , location getproviders . PackageLocation ) {
view . LogInitMessage ( views . InstallingProviderMessage , provider . ForDisplay ( ) , version )
view . Log ( "location = " + location . String ( ) )
} ,
FetchPackageSafetyCheck : func ( provider addrs . Provider , version getproviders . Version , location getproviders . PackageLocation ) error {
// If there are no safe opts the calling code has decided there's no need to be cautious
// in the current scenario.
if safeOpts != nil {
if slices . Contains ( safeOpts . providers , provider ) {
switch location . ( type ) {
case getproviders . PackageLocalDir :
// Ok, as providers sourced from the local directory are considered trusted.
return nil
case getproviders . PackageLocalArchive :
// Ok, as providers sourced from a local archive are considered trusted.
return nil
case getproviders . PackageHTTPURL :
if safeOpts . safeInitEnabled {
// Code elsewhere will enforce safe installation - allow
return nil
} else {
// Unsafe - block
return getproviders . ErrUnsafeStateStorageProviderDownload {
Provider : provider ,
Version : version ,
}
}
default :
panic ( fmt . Sprintf ( "unexpected install location for provider %s %s: %s" , provider , version , location ) )
}
}
}
return nil
} ,
QueryPackagesFailure : func ( provider addrs . Provider , err error ) {
switch errorTy := err . ( type ) {
@ -1095,7 +1149,6 @@ func (c *InitCommand) prepareInstallerEvents(ctx context.Context, reqs providerr
) ,
) )
}
} ,
QueryPackagesWarning : func ( provider addrs . Provider , warnings [ ] string ) {
displayWarnings := make ( [ ] string , len ( warnings ) )
@ -1181,6 +1234,16 @@ func (c *InitCommand) prepareInstallerEvents(ctx context.Context, reqs providerr
// but rather just emit a single general message about it at
// the end, by checking ctx.Err().
case getproviders . ErrUnsafeStateStorageProviderDownload :
diags = diags . Append ( tfdiags . Sourceless (
tfdiags . Error ,
"Unsafe init - TODO" ,
fmt . Sprintf (
"TODO - blocked download of provider %s v%s." ,
err . Provider , err . Version ,
) ,
) )
default :
// We can potentially end up in here under cancellation too,
// in spite of our getproviders.ErrRequestCanceled case above,