Skip to content

Commit f6cce9a

Browse files
committed
inject provider installer hook
1 parent 852b3ef commit f6cce9a

4 files changed

Lines changed: 24 additions & 29 deletions

File tree

internal/command/init.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ const (
392392
// The dependency lock file itself isn't updated here.
393393
//
394394
// Calling code is responsible for validating inputs to this method, e.g. mutually exclusive flags.
395-
func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *configs.Config, upgrade bool, pluginDirs []string, flagLockfile string, view views.Init, installerHook *providerInstallerHook) (output bool, resultingLocks *depsfile.Locks, safeInitAction SafeInitAction, authResult *getproviders.PackageAuthenticationResult, diags tfdiags.Diagnostics) {
395+
func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *configs.Config, upgrade bool, pluginDirs []string, flagLockfile string, view views.Init, installerHook *providerPolicyHook) (output bool, resultingLocks *depsfile.Locks, safeInitAction SafeInitAction, authResult *getproviders.PackageAuthenticationResult, diags tfdiags.Diagnostics) {
396396
if config == nil {
397397
return false, nil, SafeInitActionNotRelevant, nil, diags
398398
}
@@ -515,7 +515,6 @@ func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *config
515515
ProvidersFetched: providersFetchedCallback(view),
516516
}
517517
ctx = evts.OnContext(ctx)
518-
inst.SetHook(installerHook)
519518

520519
mode := providercache.InstallNewProvidersOnly
521520
if upgrade {
@@ -531,7 +530,7 @@ func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *config
531530

532531
// Determine which required providers are already downloaded, and download any
533532
// new providers or newer versions of providers
534-
configLocks, installErr := inst.EnsureProviderVersions(ctx, previousLocks, reqs, mode)
533+
configLocks, installErr := inst.EnsureProviderVersions(ctx, previousLocks, reqs, mode, installerHook)
535534
if ctx.Err() == context.Canceled {
536535
diags = diags.Append(fmt.Errorf("Provider installation was canceled by an interrupt signal."))
537536
view.Diagnostics(diags) // TODO: Why is the output viewed here?
@@ -590,7 +589,7 @@ func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *config
590589
// The calling code is assumed to have already called getProvidersFromConfig, which is used to
591590
// supply the configLocks argument.
592591
// The dependency lock file itself isn't updated here.
593-
func (c *InitCommand) getProvidersFromState(ctx context.Context, state *states.State, configReqs providerreqs.Requirements, configLocks *depsfile.Locks, pluginDirs []string, view views.Init, installerHook *providerInstallerHook) (output bool, resultingLocks *depsfile.Locks, diags tfdiags.Diagnostics) {
592+
func (c *InitCommand) getProvidersFromState(ctx context.Context, state *states.State, configReqs providerreqs.Requirements, configLocks *depsfile.Locks, pluginDirs []string, view views.Init, installerHook *providerPolicyHook) (output bool, resultingLocks *depsfile.Locks, diags tfdiags.Diagnostics) {
594593
ctx, span := tracer.Start(ctx, "install providers from state")
595594
defer span.End()
596595

@@ -695,7 +694,6 @@ func (c *InitCommand) getProvidersFromState(ctx context.Context, state *states.S
695694
ProvidersFetched: providersFetchedCallback(view),
696695
}
697696
ctx = evts.OnContext(ctx)
698-
inst.SetHook(installerHook)
699697

700698
mode := providercache.InstallNewProvidersOnly
701699

@@ -705,7 +703,7 @@ func (c *InitCommand) getProvidersFromState(ctx context.Context, state *states.S
705703
// would remove the effects of version constraints from the config.
706704
// > Any validation of CLI flag usage is already done in getProvidersFromConfig
707705

708-
newLocks, err := inst.EnsureProviderVersions(ctx, inProgressLocks, reqs, mode)
706+
newLocks, err := inst.EnsureProviderVersions(ctx, inProgressLocks, reqs, mode, installerHook)
709707
if ctx.Err() == context.Canceled {
710708
diags = diags.Append(fmt.Errorf("Provider installation was canceled by an interrupt signal."))
711709
view.Diagnostics(diags)

internal/command/init_run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ func (c *InitCommand) run(initArgs *arguments.Init, view views.Init) int {
248248
return 1
249249
}
250250
policyResults := plans.NewPolicyResults()
251-
providerHook := &providerInstallerHook{
251+
providerHook := &providerPolicyHook{
252252
Client: client,
253253
Reqs: reqsByModule,
254254
policyResults: policyResults,

internal/command/meta_policy.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,15 @@ func (h *policyModuleInstallHook) EvaluatePolicy(ctx context.Context, req *confi
159159
return nil
160160
}
161161

162-
type providerInstallerHook struct {
162+
type providerPolicyHook struct {
163163
Reqs *configs.ModuleRequirements
164164
Client policy.Client
165165
moduleMap map[addrs.Provider]string
166166
policyResults *plans.PolicyResults
167167
config *configs.Config
168168
}
169169

170-
func (p *providerInstallerHook) moduleSources() map[addrs.Provider]string {
170+
func (p *providerPolicyHook) moduleSources() map[addrs.Provider]string {
171171
if p.moduleMap != nil {
172172
return p.moduleMap
173173
}
@@ -199,10 +199,13 @@ func (p *providerInstallerHook) moduleSources() map[addrs.Provider]string {
199199
return p.moduleMap
200200
}
201201

202-
func (p *providerInstallerHook) EvaluatePolicy(ctx context.Context, provider addrs.Provider, version string) policy.EvaluationResponse {
202+
// ProviderVersionSelected satisfies the [providers.InstallerHook] interface.
203+
// When a provider version is selected, this method performs policy evaluation for the provider,
204+
// and aborts the installation if the policy evaluation fails.
205+
func (p *providerPolicyHook) ProviderVersionSelected(ctx context.Context, provider addrs.Provider, version string) error {
203206
// If the client is nil, then policy evaluation is disabled, so we can skip.
204207
if p.Client == nil {
205-
return policy.EvaluationResponse{}
208+
return nil
206209
}
207210
moduleSources := p.moduleSources()
208211
log.Println("[DEBUG] init: evaluating policy for provider", provider.String(), version)
@@ -227,5 +230,5 @@ func (p *providerInstallerHook) EvaluatePolicy(ctx context.Context, provider add
227230

228231
p.policyResults.AddProvider(addr, result, providerConfig)
229232

230-
return result
233+
return fmt.Errorf("Provider download failed due to policy violations. Please review other diagnostics for details.")
231234
}

internal/providercache/installer.go

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
copydir "github.com/hashicorp/terraform/internal/copy"
1818
"github.com/hashicorp/terraform/internal/depsfile"
1919
"github.com/hashicorp/terraform/internal/getproviders"
20-
"github.com/hashicorp/terraform/internal/policy"
2120
)
2221

2322
// Installer is the main type in this package, representing a provider installer
@@ -59,10 +58,6 @@ type Installer struct {
5958
// lifecycle for, and therefore does not need to worry about the
6059
// installation of.
6160
unmanagedProviderTypes map[addrs.Provider]struct{}
62-
63-
// hook is an optional hook whose methods may be called for each provider
64-
// version that is being installed or upgraded.
65-
hook InstallerHook
6661
}
6762

6863
// NewInstaller constructs and returns a new installer with the given target
@@ -166,10 +161,6 @@ func (i *Installer) SetUnmanagedProviderTypes(types map[addrs.Provider]struct{})
166161
i.unmanagedProviderTypes = types
167162
}
168163

169-
func (i *Installer) SetHook(hook InstallerHook) {
170-
i.hook = hook
171-
}
172-
173164
// EnsureProviderVersions compares the given provider requirements with what
174165
// is already available in the installer's target directory and then takes
175166
// appropriate installation actions to ensure that suitable packages
@@ -189,7 +180,7 @@ func (i *Installer) SetHook(hook InstallerHook) {
189180
// failures then those notifications will be redundant with the ones included
190181
// in the final returned error value so callers should show either one or the
191182
// other, and not both.
192-
func (i *Installer) EnsureProviderVersions(ctx context.Context, locks *depsfile.Locks, reqs getproviders.Requirements, mode InstallMode) (*depsfile.Locks, error) {
183+
func (i *Installer) EnsureProviderVersions(ctx context.Context, locks *depsfile.Locks, reqs getproviders.Requirements, mode InstallMode, hooks ...InstallerHook) (*depsfile.Locks, error) {
193184
errs := map[addrs.Provider]error{}
194185
evts := installerEventsForContext(ctx)
195186

@@ -352,19 +343,19 @@ NeedProvider:
352343
return nil, err
353344
}
354345

355-
if i.hook != nil {
346+
for _, hook := range hooks {
356347
// For each needed provider, we will send the version
357348
// and provider to the hook for policy evaluation.
358349
// If the hook returns an error, we'll abort the installation.
359350
// We do this before checking the lock file, so that we also
360351
// evaluate policy for providers that are already installed.
361-
result := i.hook.EvaluatePolicy(ctx, provider, version.String())
352+
err := hook.ProviderVersionSelected(ctx, provider, version.String())
362353

363354
// return a generic error here that the init command returns to the CLI.
364355
// The detailed policy diagnostics are included in the policy results
365356
// and will be formatted in the CLI output.
366-
if len(result.Diagnostics) > 0 && result.Diagnostics.AsTerraformDiags().HasErrors() {
367-
return nil, fmt.Errorf("Provider download failed due to policy violations. Please review other diagnostics for details.")
357+
if err != nil {
358+
return nil, err
368359
}
369360
}
370361

@@ -806,7 +797,10 @@ func (err InstallerError) Error() string {
806797
}
807798

808799
type InstallerHook interface {
809-
// EvaluatePolicy is called for each provider version that is being installed
810-
// or upgraded, allowing the caller to implement custom policy evaluation.
811-
EvaluatePolicy(ctx context.Context, provider addrs.Provider, version string) policy.EvaluationResponse
800+
// ProviderVersionSelected is called after the installer has selected a provider
801+
// version and before it decides whether install the selected package, either from
802+
// the local cache or from a remote registry.
803+
//
804+
// Returning an error aborts installation.
805+
ProviderVersionSelected(ctx context.Context, provider addrs.Provider, version string) error
812806
}

0 commit comments

Comments
 (0)