Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/command/arguments/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ type Init struct {
// TODO(SarahFrench/radeksimko): Remove this once the feature is no longer
// experimental
EnablePssExperiment bool

// PolicyPath contains an optional path to any defined policies that should
// be applied for this plan operation.
PolicyPaths []string
}

// ParseInit processes CLI arguments, returning an Init value and errors.
Expand Down Expand Up @@ -112,6 +116,7 @@ func ParseInit(args []string, experimentsEnabled bool) (*Init, tfdiags.Diagnosti
cmdFlags.BoolVar(&init.Json, "json", false, "json")
cmdFlags.Var(&init.BackendConfig, "backend-config", "")
cmdFlags.Var(&init.PluginPath, "plugin-dir", "plugin directory")
cmdFlags.Var((*FlagStringSlice)(&init.PolicyPaths), "policies", "policies")

// Used for enabling experimental code that's invoked before configuration is parsed.
cmdFlags.BoolVar(&init.EnablePssExperiment, "enable-pluggable-state-storage-experiment", false, "Enable the pluggable state storage experiment")
Expand Down
2 changes: 1 addition & 1 deletion internal/command/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func testModuleWithSnapshot(t *testing.T, name string) (*configs.Config, *config
// sources only this ultimately just records all of the module paths
// in a JSON file so that we can load them below.
inst := initwd.NewModuleInstaller(loader.ModulesDir(), loader, registry.NewClient(nil, nil), nil)
_, instDiags := inst.InstallModules(context.Background(), dir, "tests", true, false, initwd.ModuleInstallHooksImpl{})
_, instDiags := inst.InstallModules(context.Background(), dir, "tests", true, false)
if instDiags.HasErrors() {
t.Fatal(instDiags.Err())
}
Expand Down
2 changes: 1 addition & 1 deletion internal/command/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func TestGraph_resourcesOnly(t *testing.T) {
t.Fatal(err)
}
inst := initwd.NewModuleInstaller(".terraform/modules", loader, registry.NewClient(nil, nil), nil)
_, instDiags := inst.InstallModules(context.Background(), ".", "tests", true, false, initwd.ModuleInstallHooksImpl{})
_, instDiags := inst.InstallModules(context.Background(), ".", "tests", true, false)
if instDiags.HasErrors() {
t.Fatal(instDiags.Err())
}
Expand Down
4 changes: 2 additions & 2 deletions internal/command/hook_module_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ type view interface {
Log(message string, params ...any)
}
type uiModuleInstallHooks struct {
initwd.ModuleInstallHooksImpl
initwd.ModuleInstallHookImpl
Ui cli.Ui
ShowLocalPaths bool
View view
}

var _ initwd.ModuleInstallHooks = uiModuleInstallHooks{}
var _ initwd.ModuleInstallHook = uiModuleInstallHooks{}

func (h uiModuleInstallHooks) Download(modulePath, packageAddr string, v *version.Version) {
if v != nil {
Expand Down
41 changes: 28 additions & 13 deletions internal/command/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import (
"github.com/hashicorp/terraform/internal/getproviders"
"github.com/hashicorp/terraform/internal/getproviders/providerreqs"
"github.com/hashicorp/terraform/internal/getproviders/reattach"
"github.com/hashicorp/terraform/internal/initwd"
"github.com/hashicorp/terraform/internal/plans"
"github.com/hashicorp/terraform/internal/policy"
"github.com/hashicorp/terraform/internal/providercache"
"github.com/hashicorp/terraform/internal/states"
"github.com/hashicorp/terraform/internal/tfdiags"
Expand Down Expand Up @@ -76,7 +79,7 @@ func (c *InitCommand) Run(args []string) int {
return c.run(initArgs, view)
}

func (c *InitCommand) getModules(ctx context.Context, path, testsDir string, earlyRoot *configs.Module, upgrade bool, view views.Init) (output bool, abort bool, diags tfdiags.Diagnostics) {
func (c *InitCommand) getModules(ctx context.Context, path, testsDir string, earlyRoot *configs.Module, upgrade bool, view views.Init, policyClient policy.Client) (output bool, abort bool, policyResults *plans.PolicyResults, diags tfdiags.Diagnostics) {
testModules := false // We can also have modules buried in test files.
for _, file := range earlyRoot.Tests {
for _, run := range file.Runs {
Expand All @@ -88,7 +91,7 @@ func (c *InitCommand) getModules(ctx context.Context, path, testsDir string, ear

if len(earlyRoot.ModuleCalls) == 0 && !testModules {
// Nothing to do
return false, false, nil
return false, false, nil, nil
}

ctx, span := tracer.Start(ctx, "install modules", trace.WithAttributes(
Expand All @@ -102,13 +105,24 @@ func (c *InitCommand) getModules(ctx context.Context, path, testsDir string, ear
view.Output(views.InitializingModulesMessage)
}

hooks := uiModuleInstallHooks{
uiHook := uiModuleInstallHooks{
Ui: c.Ui,
ShowLocalPaths: true,
View: view,
}
hooks := []initwd.ModuleInstallHook{uiHook}
var policyHook *policyModuleInstallHook
if policyClient != nil {
policyResults = plans.NewPolicyResults()
policyHook = &policyModuleInstallHook{
client: policyClient,
rootModule: earlyRoot,
policyResults: policyResults,
}
hooks = append(hooks, policyHook)
}

installAbort, installDiags := c.installModules(ctx, path, testsDir, upgrade, false, hooks)
installAbort, installDiags := c.installModules(ctx, path, testsDir, upgrade, false, hooks...)
diags = diags.Append(installDiags)

// At this point, installModules may have generated error diags or been
Expand All @@ -128,7 +142,7 @@ func (c *InitCommand) getModules(ctx context.Context, path, testsDir string, ear
}
}

return true, installAbort, diags
return true, installAbort, policyResults, diags
}

func (c *InitCommand) initCloud(ctx context.Context, root *configs.Module, extraConfig arguments.FlagNameValueSlice, viewType arguments.ViewType, view views.Init) (be backend.Backend, output bool, diags tfdiags.Diagnostics) {
Expand Down Expand Up @@ -364,7 +378,7 @@ the backend configuration is present and valid.
// 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 []string, flagLockfile string, view views.Init, installerHook *providerInstallerHook) (output bool, resultingLocks *depsfile.Locks, diags tfdiags.Diagnostics) {
ctx, span := tracer.Start(ctx, "install providers from config")
defer span.End()

Expand Down Expand Up @@ -422,6 +436,7 @@ func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *config

evts := c.prepareInstallerEvents(ctx, reqs, &diags, inst, view, views.InitializingProviderPluginFromConfigMessage, views.ReusingPreviousVersionInfo)
ctx = evts.OnContext(ctx)
inst.SetHook(installerHook)

mode := providercache.InstallNewProvidersOnly
if upgrade {
Expand All @@ -443,20 +458,19 @@ func (c *InitCommand) getProvidersFromConfig(ctx context.Context, config *config

// Determine which required providers are already downloaded, and download any
// new providers or newer versions of providers
configLocks, err := inst.EnsureProviderVersions(ctx, previousLocks, reqs, mode)
configLocks, installErr := inst.EnsureProviderVersions(ctx, previousLocks, reqs, mode)
if ctx.Err() == context.Canceled {
diags = diags.Append(fmt.Errorf("Provider installation was canceled by an interrupt signal."))
view.Diagnostics(diags)
view.Diagnostics(diags) // TODO: Why is the output viewed here?
return true, nil, diags
}
if err != nil {
// The errors captured in "err" should be redundant with what we
if installErr != nil {
// The errors captured in "installErr" should be redundant with what we
// received via the InstallerEvents callbacks above, so we'll
// just return those as long as we have some.
if !diags.HasErrors() {
diags = diags.Append(err)
diags = diags.Append(installErr)
}

return true, nil, diags
}

Expand All @@ -469,7 +483,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, configReqs providerreqs.Requirements, 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, configReqs providerreqs.Requirements, configLocks *depsfile.Locks, upgrade bool, pluginDirs []string, flagLockfile string, view views.Init, installerHook *providerInstallerHook) (output bool, resultingLocks *depsfile.Locks, diags tfdiags.Diagnostics) {
ctx, span := tracer.Start(ctx, "install providers from state")
defer span.End()

Expand Down Expand Up @@ -547,6 +561,7 @@ func (c *InitCommand) getProvidersFromState(ctx context.Context, state *states.S
// are shimming our vt100 output to the legacy console API on Windows.
evts := c.prepareInstallerEvents(ctx, reqs, &diags, inst, view, views.InitializingProviderPluginFromStateMessage, views.ReusingVersionIdentifiedFromConfig)
ctx = evts.OnContext(ctx)
inst.SetHook(installerHook)

mode := providercache.InstallNewProvidersOnly

Expand Down
Loading