131 lines
4.4 KiB
Go
131 lines
4.4 KiB
Go
package earlyconfig
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
|
|
version "github.com/hashicorp/go-version"
|
|
"github.com/hashicorp/terraform-config-inspect/tfconfig"
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/moduledeps"
|
|
"github.com/hashicorp/terraform/plugin/discovery"
|
|
"github.com/hashicorp/terraform/tfdiags"
|
|
)
|
|
|
|
// A Config is a node in the tree of modules within a configuration.
|
|
//
|
|
// The module tree is constructed by following ModuleCall instances recursively
|
|
// through the root module transitively into descendent modules.
|
|
type Config struct {
|
|
// RootModule points to the Config for the root module within the same
|
|
// module tree as this module. If this module _is_ the root module then
|
|
// this is self-referential.
|
|
Root *Config
|
|
|
|
// ParentModule points to the Config for the module that directly calls
|
|
// this module. If this is the root module then this field is nil.
|
|
Parent *Config
|
|
|
|
// Path is a sequence of module logical names that traverse from the root
|
|
// module to this config. Path is empty for the root module.
|
|
//
|
|
// This should only be used to display paths to the end-user in rare cases
|
|
// where we are talking about the static module tree, before module calls
|
|
// have been resolved. In most cases, an addrs.ModuleInstance describing
|
|
// a node in the dynamic module tree is better, since it will then include
|
|
// any keys resulting from evaluating "count" and "for_each" arguments.
|
|
Path addrs.Module
|
|
|
|
// ChildModules points to the Config for each of the direct child modules
|
|
// called from this module. The keys in this map match the keys in
|
|
// Module.ModuleCalls.
|
|
Children map[string]*Config
|
|
|
|
// Module points to the object describing the configuration for the
|
|
// various elements (variables, resources, etc) defined by this module.
|
|
Module *tfconfig.Module
|
|
|
|
// CallPos is the source position for the header of the module block that
|
|
// requested this module.
|
|
//
|
|
// This field is meaningless for the root module, where its contents are undefined.
|
|
CallPos tfconfig.SourcePos
|
|
|
|
// SourceAddr is the source address that the referenced module was requested
|
|
// from, as specified in configuration.
|
|
//
|
|
// This field is meaningless for the root module, where its contents are undefined.
|
|
SourceAddr string
|
|
|
|
// Version is the specific version that was selected for this module,
|
|
// based on version constraints given in configuration.
|
|
//
|
|
// This field is nil if the module was loaded from a non-registry source,
|
|
// since versions are not supported for other sources.
|
|
//
|
|
// This field is meaningless for the root module, where it will always
|
|
// be nil.
|
|
Version *version.Version
|
|
}
|
|
|
|
// ProviderDependencies returns the provider dependencies for the recieving
|
|
// config, including all of its descendent modules.
|
|
func (c *Config) ProviderDependencies() (*moduledeps.Module, tfdiags.Diagnostics) {
|
|
var diags tfdiags.Diagnostics
|
|
|
|
var name string
|
|
if len(c.Path) > 0 {
|
|
name = c.Path[len(c.Path)-1]
|
|
}
|
|
|
|
ret := &moduledeps.Module{
|
|
Name: name,
|
|
}
|
|
|
|
providers := make(moduledeps.Providers)
|
|
for name, reqs := range c.Module.RequiredProviders {
|
|
fqn, diags := addrs.ParseProviderSourceString(name)
|
|
if diags.HasErrors() {
|
|
diags = diags.Append(wrapDiagnostic(tfconfig.Diagnostic{
|
|
Severity: tfconfig.DiagError,
|
|
Summary: "Invalid provider source",
|
|
Detail: fmt.Sprintf("Invalid source %q for provider", name),
|
|
}))
|
|
}
|
|
var constraints version.Constraints
|
|
for _, reqStr := range reqs.VersionConstraints {
|
|
if reqStr != "" {
|
|
constraint, err := version.NewConstraint(reqStr)
|
|
if err != nil {
|
|
diags = diags.Append(wrapDiagnostic(tfconfig.Diagnostic{
|
|
Severity: tfconfig.DiagError,
|
|
Summary: "Invalid provider version constraint",
|
|
Detail: fmt.Sprintf("Invalid version constraint %q for provider %s.", reqStr, fqn.LegacyString()),
|
|
}))
|
|
continue
|
|
}
|
|
constraints = append(constraints, constraint...)
|
|
}
|
|
}
|
|
providers[fqn] = moduledeps.ProviderDependency{
|
|
Constraints: discovery.NewConstraints(constraints),
|
|
Reason: moduledeps.ProviderDependencyExplicit,
|
|
}
|
|
}
|
|
ret.Providers = providers
|
|
|
|
childNames := make([]string, 0, len(c.Children))
|
|
for name := range c.Children {
|
|
childNames = append(childNames, name)
|
|
}
|
|
sort.Strings(childNames)
|
|
|
|
for _, name := range childNames {
|
|
child, childDiags := c.Children[name].ProviderDependencies()
|
|
ret.Children = append(ret.Children, child)
|
|
diags = diags.Append(childDiags)
|
|
}
|
|
|
|
return ret, diags
|
|
}
|