Skip to content

Commit

Permalink
allow config errors when using -from-module
Browse files Browse the repository at this point in the history
When initializing the working directory from a module, some use cases
may still want the module source even when the configuration cannot be
loaded due to validation errors.

Isolate the installation errors during the initialization sequence, so
we can report them if there is a problem fetching the actual module
source. Once we have the module, convert configuration errors to
warnings so the cli initialization can proceed.
  • Loading branch information
jbardin authored and pull[bot] committed Aug 28, 2023
1 parent 3b75313 commit 837ac5a
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 14 deletions.
37 changes: 34 additions & 3 deletions internal/initwd/from_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const initFromModuleRootKeyPrefix = initFromModuleRootCallName + "."
// are produced in that case, to prompt the user to rewrite the source strings
// to be absolute references to the original remote module.
func DirFromModule(ctx context.Context, loader *configload.Loader, rootDir, modulesDir, sourceAddrStr string, reg *registry.Client, hooks ModuleInstallHooks) tfdiags.Diagnostics {

var diags tfdiags.Diagnostics

// The way this function works is pretty ugly, but we accept it because
Expand Down Expand Up @@ -157,13 +158,43 @@ func DirFromModule(ctx context.Context, loader *configload.Loader, rootDir, modu
wrapHooks := installHooksInitDir{
Wrapped: hooks,
}
// Create a manifest record for the root module. This will be used if
// there are any relative-pathed modules in the root.
instManifest[""] = modsdir.Record{
Key: "",
Dir: rootDir,
}
fetcher := getmodules.NewPackageFetcher()
_, instDiags := inst.installDescendentModules(ctx, fakeRootModule, rootDir, instManifest, true, wrapHooks, fetcher)
diags = append(diags, instDiags...)

// When attempting to initialize the current directory with a module
// source, some use cases may want to ignore configuration errors from the
// building of the entire configuration structure, but we still need to
// capture installation errors. Because the actual module installation
// happens in the ModuleWalkFunc callback while building the config, we
// need to create a closure to capture the installation diagnostics
// separately.
var instDiags hcl.Diagnostics
w := inst.moduleInstallWalker(ctx, instManifest, true, wrapHooks, fetcher)
walker := configs.ModuleWalkerFunc(func(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
mod, version, diags := w.LoadModule(req)
instDiags = instDiags.Extend(diags)
return mod, version, diags
})

_, cDiags := inst.installDescendentModules(fakeRootModule, instManifest, walker)
// We can't continue if there was an error during installation, but return
// all diagnostics in case there happens to be anything else useful when
// debugging the problem.
if instDiags.HasErrors() {
return diags
return diags.Append(cDiags)
}

// if there are errors here, they must be only from building the config
// structures. We don't want to block initialization at this point, so
// convert these into warnings. Any actual errors in the configuration will
// be raised as soon as the config is loaded again.
diags = append(diags, tfdiags.OverrideAll(cDiags, tfdiags.Warning, nil)...)

// If all of that succeeded then we'll now migrate what was installed
// into the final directory structure.
err = os.MkdirAll(modulesDir, os.ModePerm)
Expand Down
28 changes: 17 additions & 11 deletions internal/initwd/module_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,6 @@ func (i *ModuleInstaller) InstallModules(ctx context.Context, rootDir, testsDir
}

fetcher := getmodules.NewPackageFetcher()
cfg, instDiags := i.installDescendentModules(ctx, rootMod, rootDir, manifest, upgrade, hooks, fetcher)
diags = append(diags, instDiags...)

return cfg, diags
}

func (i *ModuleInstaller) installDescendentModules(ctx context.Context, rootMod *configs.Module, rootDir string, manifest modsdir.Manifest, upgrade bool, hooks ModuleInstallHooks, fetcher *getmodules.PackageFetcher) (*configs.Config, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics

if hooks == nil {
// Use our no-op implementation as a placeholder
Expand All @@ -135,8 +127,16 @@ func (i *ModuleInstaller) installDescendentModules(ctx context.Context, rootMod
Key: "",
Dir: rootDir,
}
walker := i.moduleInstallWalker(ctx, manifest, upgrade, hooks, fetcher)

cfg, instDiags := i.installDescendentModules(rootMod, manifest, walker)
diags = append(diags, instDiags...)

cfg, cDiags := configs.BuildConfig(rootMod, configs.ModuleWalkerFunc(
return cfg, diags
}

func (i *ModuleInstaller) moduleInstallWalker(ctx context.Context, manifest modsdir.Manifest, upgrade bool, hooks ModuleInstallHooks, fetcher *getmodules.PackageFetcher) configs.ModuleWalker {
return configs.ModuleWalkerFunc(
func(req *configs.ModuleRequest) (*configs.Module, *version.Version, hcl.Diagnostics) {
var diags hcl.Diagnostics

Expand Down Expand Up @@ -273,9 +273,15 @@ func (i *ModuleInstaller) installDescendentModules(ctx context.Context, rootMod
// of addrs.ModuleSource.
panic(fmt.Sprintf("unsupported module source address %#v", addr))
}

},
))
)
}

func (i *ModuleInstaller) installDescendentModules(rootMod *configs.Module, manifest modsdir.Manifest, installWalker configs.ModuleWalker) (*configs.Config, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics

cfg, cDiags := configs.BuildConfig(rootMod, installWalker)

diags = diags.Append(cDiags)

err := manifest.WriteSnapshotToDir(i.modsDir)
Expand Down

0 comments on commit 837ac5a

Please sign in to comment.