terraform: HCL2-flavored module dependency resolver
For the moment this is just a lightly-adapted copy of ModuleTreeDependencies named ConfigTreeDependencies, with the goal that the two can live concurrently for the moment while not all callers are yet updated and then we can drop ModuleTreeDependencies and its helper functions altogether in a later commit. This can then be used to make "terraform init" and "terraform providers" work properly with the HCL2-powered configuration loader.
This commit is contained in:
parent
ebafa51723
commit
4ed06a9227
|
@ -7,7 +7,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
multierror "github.com/hashicorp/go-multierror"
|
|
||||||
"github.com/hashicorp/hcl2/hcl"
|
"github.com/hashicorp/hcl2/hcl"
|
||||||
"github.com/hashicorp/terraform/backend"
|
"github.com/hashicorp/terraform/backend"
|
||||||
backendinit "github.com/hashicorp/terraform/backend/init"
|
backendinit "github.com/hashicorp/terraform/backend/init"
|
||||||
|
@ -145,6 +144,8 @@ func (c *InitCommand) Run(args []string) int {
|
||||||
c.showDiagnostics(diags)
|
c.showDiagnostics(diags)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Ui.Output("")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If our directory is empty, then we're done. We can't get or setup
|
// If our directory is empty, then we're done. We can't get or setup
|
||||||
|
@ -289,10 +290,10 @@ func (c *InitCommand) Run(args []string) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we have loaded all modules, check the module tree for missing providers.
|
// Now that we have loaded all modules, check the module tree for missing providers.
|
||||||
err = c.getProviders(path, state, flagUpgrade)
|
providerDiags := c.getProviders(path, state, flagUpgrade)
|
||||||
if err != nil {
|
diags = diags.Append(providerDiags)
|
||||||
// this function provides its own output
|
if providerDiags.HasErrors() {
|
||||||
log.Printf("[ERROR] %s", err)
|
c.showDiagnostics(diags)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +303,11 @@ func (c *InitCommand) Run(args []string) int {
|
||||||
c.Ui.Output("")
|
c.Ui.Output("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we accumulated any warnings along the way that weren't accompanied
|
||||||
|
// by errors then we'll output them here so that the success message is
|
||||||
|
// still the final thing shown.
|
||||||
|
c.showDiagnostics(diags)
|
||||||
|
|
||||||
c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccess)))
|
c.Ui.Output(c.Colorize().Color(strings.TrimSpace(outputInitSuccess)))
|
||||||
if !c.RunningInAutomation {
|
if !c.RunningInAutomation {
|
||||||
// If we're not running in an automation wrapper, give the user
|
// If we're not running in an automation wrapper, give the user
|
||||||
|
@ -384,24 +390,25 @@ func (c *InitCommand) backendConfigOverrideBody(flags rawFlags, schema *configsc
|
||||||
|
|
||||||
// Load the complete module tree, and fetch any missing providers.
|
// Load the complete module tree, and fetch any missing providers.
|
||||||
// This method outputs its own Ui.
|
// This method outputs its own Ui.
|
||||||
func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade bool) error {
|
func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade bool) tfdiags.Diagnostics {
|
||||||
mod, diags := c.Module(path)
|
config, diags := c.loadConfig(path)
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
c.showDiagnostics(diags)
|
return diags
|
||||||
return diags.Err()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := terraform.CheckStateVersion(state); err != nil {
|
if err := terraform.CheckStateVersion(state); err != nil {
|
||||||
diags = diags.Append(err)
|
diags = diags.Append(err)
|
||||||
c.showDiagnostics(diags)
|
return diags
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := terraform.CheckRequiredVersion(mod); err != nil {
|
// FIXME: Restore this once terraform.CheckRequiredVersion is updated to
|
||||||
diags = diags.Append(err)
|
// work with a configs.Config instead of a legacy module.Tree.
|
||||||
c.showDiagnostics(diags)
|
/*
|
||||||
return err
|
if err := terraform.CheckRequiredVersion(mod); err != nil {
|
||||||
}
|
diags = diags.Append(err)
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
var available discovery.PluginMetaSet
|
var available discovery.PluginMetaSet
|
||||||
if upgrade {
|
if upgrade {
|
||||||
|
@ -412,7 +419,7 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
available = c.providerPluginSet()
|
available = c.providerPluginSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
requirements := terraform.ModuleTreeDependencies(mod, state).AllPluginRequirements()
|
requirements := terraform.ConfigTreeDependencies(config, state).AllPluginRequirements()
|
||||||
if len(requirements) == 0 {
|
if len(requirements) == 0 {
|
||||||
// nothing to initialize
|
// nothing to initialize
|
||||||
return nil
|
return nil
|
||||||
|
@ -424,7 +431,6 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
|
|
||||||
missing := c.missingPlugins(available, requirements)
|
missing := c.missingPlugins(available, requirements)
|
||||||
|
|
||||||
var errs error
|
|
||||||
if c.getPlugins {
|
if c.getPlugins {
|
||||||
if len(missing) > 0 {
|
if len(missing) > 0 {
|
||||||
c.Ui.Output(fmt.Sprintf("- Checking for available provider plugins on %s...",
|
c.Ui.Output(fmt.Sprintf("- Checking for available provider plugins on %s...",
|
||||||
|
@ -461,12 +467,12 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
c.Ui.Error(fmt.Sprintf(errProviderInstallError, provider, err.Error(), DefaultPluginVendorDir))
|
c.Ui.Error(fmt.Sprintf(errProviderInstallError, provider, err.Error(), DefaultPluginVendorDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = multierror.Append(errs, err)
|
diags = diags.Append(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs != nil {
|
if diags.HasErrors() {
|
||||||
return errs
|
return diags
|
||||||
}
|
}
|
||||||
} else if len(missing) > 0 {
|
} else if len(missing) > 0 {
|
||||||
// we have missing providers, but aren't going to try and download them
|
// we have missing providers, but aren't going to try and download them
|
||||||
|
@ -477,11 +483,11 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
} else {
|
} else {
|
||||||
lines = append(lines, fmt.Sprintf("* %s (%s)\n", provider, reqd.Versions))
|
lines = append(lines, fmt.Sprintf("* %s (%s)\n", provider, reqd.Versions))
|
||||||
}
|
}
|
||||||
errs = multierror.Append(errs, fmt.Errorf("missing provider %q", provider))
|
diags = diags.Append(fmt.Errorf("missing provider %q", provider))
|
||||||
}
|
}
|
||||||
sort.Strings(lines)
|
sort.Strings(lines)
|
||||||
c.Ui.Error(fmt.Sprintf(errMissingProvidersNoInstall, strings.Join(lines, ""), DefaultPluginVendorDir))
|
c.Ui.Error(fmt.Sprintf(errMissingProvidersNoInstall, strings.Join(lines, ""), DefaultPluginVendorDir))
|
||||||
return errs
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// With all the providers downloaded, we'll generate our lock file
|
// With all the providers downloaded, we'll generate our lock file
|
||||||
|
@ -497,8 +503,8 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
for name, meta := range chosen {
|
for name, meta := range chosen {
|
||||||
digest, err := meta.SHA256()
|
digest, err := meta.SHA256()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("failed to read provider plugin %s: %s", meta.Path, err))
|
diags = diags.Append(fmt.Errorf("Failed to read provider plugin %s: %s", meta.Path, err))
|
||||||
return err
|
return diags
|
||||||
}
|
}
|
||||||
digests[name] = digest
|
digests[name] = digest
|
||||||
if c.ignorePluginChecksum {
|
if c.ignorePluginChecksum {
|
||||||
|
@ -507,8 +513,8 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
}
|
}
|
||||||
err := c.providerPluginsLock().Write(digests)
|
err := c.providerPluginsLock().Write(digests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("failed to save provider manifest: %s", err))
|
diags = diags.Append(fmt.Errorf("failed to save provider manifest: %s", err))
|
||||||
return err
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -556,7 +562,7 @@ func (c *InitCommand) getProviders(path string, state *terraform.State, upgrade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InitCommand) AutocompleteArgs() complete.Predictor {
|
func (c *InitCommand) AutocompleteArgs() complete.Predictor {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/moduledeps"
|
"github.com/hashicorp/terraform/moduledeps"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/hashicorp/terraform/tfdiags"
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
"github.com/xlab/treeprint"
|
"github.com/xlab/treeprint"
|
||||||
)
|
)
|
||||||
|
@ -69,11 +70,8 @@ func (c *ProvidersCommand) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Restore this once the "terraform" package is updated to deal
|
s := state.State()
|
||||||
// with HCL2 config types.
|
depTree := terraform.ConfigTreeDependencies(config, s)
|
||||||
//s := state.State()
|
|
||||||
//depTree := terraform.ModuleTreeDependencies(config, s)
|
|
||||||
var depTree *moduledeps.Module
|
|
||||||
depTree.SortDescendents()
|
depTree.SortDescendents()
|
||||||
|
|
||||||
printRoot := treeprint.New()
|
printRoot := treeprint.New()
|
||||||
|
|
|
@ -2,6 +2,7 @@ package configs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl2/gohcl"
|
"github.com/hashicorp/hcl2/gohcl"
|
||||||
"github.com/hashicorp/hcl2/hcl"
|
"github.com/hashicorp/hcl2/hcl"
|
||||||
|
@ -39,6 +40,22 @@ func (r *ManagedResource) moduleUniqueKey() string {
|
||||||
return fmt.Sprintf("%s.%s", r.Name, r.Type)
|
return fmt.Sprintf("%s.%s", r.Name, r.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProviderConfigKey returns a string key for the provider configuration
|
||||||
|
// that should be used for this resource. This function implements the
|
||||||
|
// default behavior of extracting the type from the resource type name if
|
||||||
|
// an explicit "provider" argument was not provided.
|
||||||
|
func (r *ManagedResource) ProviderConfigKey() string {
|
||||||
|
if r.ProviderConfigRef == nil {
|
||||||
|
typeName := r.Type
|
||||||
|
if under := strings.Index(typeName, "_"); under != -1 {
|
||||||
|
return typeName[:under]
|
||||||
|
}
|
||||||
|
return typeName
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.ProviderConfigRef.String()
|
||||||
|
}
|
||||||
|
|
||||||
func decodeResourceBlock(block *hcl.Block) (*ManagedResource, hcl.Diagnostics) {
|
func decodeResourceBlock(block *hcl.Block) (*ManagedResource, hcl.Diagnostics) {
|
||||||
r := &ManagedResource{
|
r := &ManagedResource{
|
||||||
Type: block.Labels[0],
|
Type: block.Labels[0],
|
||||||
|
@ -234,6 +251,22 @@ func (r *DataResource) moduleUniqueKey() string {
|
||||||
return fmt.Sprintf("data.%s.%s", r.Name, r.Type)
|
return fmt.Sprintf("data.%s.%s", r.Name, r.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProviderConfigKey returns a string key for the provider configuration
|
||||||
|
// that should be used for this resource. This function implements the
|
||||||
|
// default behavior of extracting the type from the resource type name if
|
||||||
|
// an explicit "provider" argument was not provided.
|
||||||
|
func (r *DataResource) ProviderConfigKey() string {
|
||||||
|
if r.ProviderConfigRef == nil {
|
||||||
|
typeName := r.Type
|
||||||
|
if under := strings.Index(typeName, "_"); under != -1 {
|
||||||
|
return typeName[:under]
|
||||||
|
}
|
||||||
|
return typeName
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.ProviderConfigRef.String()
|
||||||
|
}
|
||||||
|
|
||||||
func decodeDataBlock(block *hcl.Block) (*DataResource, hcl.Diagnostics) {
|
func decodeDataBlock(block *hcl.Block) (*DataResource, hcl.Diagnostics) {
|
||||||
r := &DataResource{
|
r := &DataResource{
|
||||||
Type: block.Labels[0],
|
Type: block.Labels[0],
|
||||||
|
@ -370,6 +403,16 @@ func decodeProviderConfigRef(attr *hcl.Attribute) (*ProviderConfigRef, hcl.Diagn
|
||||||
return ret, diags
|
return ret, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ProviderConfigRef) String() string {
|
||||||
|
if r == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
if r.Alias != "" {
|
||||||
|
return fmt.Sprintf("%s.%s", r.Name, r.Alias)
|
||||||
|
}
|
||||||
|
return r.Name
|
||||||
|
}
|
||||||
|
|
||||||
var commonResourceAttributes = []hcl.AttributeSchema{
|
var commonResourceAttributes = []hcl.AttributeSchema{
|
||||||
{
|
{
|
||||||
Name: "count",
|
Name: "count",
|
||||||
|
|
|
@ -36,6 +36,11 @@ type Constraints struct {
|
||||||
raw version.Constraints
|
raw version.Constraints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewConstraints creates a Constraints based on a version.Constraints.
|
||||||
|
func NewConstraints(c version.Constraints) Constraints {
|
||||||
|
return Constraints{c}
|
||||||
|
}
|
||||||
|
|
||||||
// AllVersions is a Constraints containing all versions
|
// AllVersions is a Constraints containing all versions
|
||||||
var AllVersions Constraints
|
var AllVersions Constraints
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,207 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
version "github.com/hashicorp/go-version"
|
||||||
"github.com/hashicorp/terraform/config"
|
"github.com/hashicorp/terraform/config"
|
||||||
"github.com/hashicorp/terraform/config/module"
|
"github.com/hashicorp/terraform/config/module"
|
||||||
|
"github.com/hashicorp/terraform/configs"
|
||||||
"github.com/hashicorp/terraform/moduledeps"
|
"github.com/hashicorp/terraform/moduledeps"
|
||||||
"github.com/hashicorp/terraform/plugin/discovery"
|
"github.com/hashicorp/terraform/plugin/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ConfigTreeDependencies returns the dependencies of the tree of modules
|
||||||
|
// described by the given configuration and state.
|
||||||
|
//
|
||||||
|
// Both configuration and state are required because there can be resources
|
||||||
|
// implied by instances in the state that no longer exist in config.
|
||||||
|
func ConfigTreeDependencies(root *configs.Config, state *State) *moduledeps.Module {
|
||||||
|
// First we walk the configuration tree to build the overall structure
|
||||||
|
// and capture the explicit/implicit/inherited provider dependencies.
|
||||||
|
deps := configTreeConfigDependencies(root, nil)
|
||||||
|
|
||||||
|
// Next we walk over the resources in the state to catch any additional
|
||||||
|
// dependencies created by existing resources that are no longer in config.
|
||||||
|
// Most things we find in state will already be present in 'deps', but
|
||||||
|
// we're interested in the rare thing that isn't.
|
||||||
|
configTreeMergeStateDependencies(deps, state)
|
||||||
|
|
||||||
|
return deps
|
||||||
|
}
|
||||||
|
|
||||||
|
func configTreeConfigDependencies(root *configs.Config, inheritProviders map[string]*configs.Provider) *moduledeps.Module {
|
||||||
|
if root == nil {
|
||||||
|
// If no config is provided, we'll make a synthetic root.
|
||||||
|
// This isn't necessarily correct if we're called with a nil that
|
||||||
|
// *isn't* at the root, but in practice that can never happen.
|
||||||
|
return &moduledeps.Module{
|
||||||
|
Name: "root",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := "root"
|
||||||
|
if len(root.Path) != 0 {
|
||||||
|
name = root.Path[len(root.Path)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := &moduledeps.Module{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
|
||||||
|
module := root.Module
|
||||||
|
|
||||||
|
// Provider dependencies
|
||||||
|
{
|
||||||
|
providers := make(moduledeps.Providers)
|
||||||
|
|
||||||
|
// The main way to declare a provider dependency is explicitly inside
|
||||||
|
// the "terraform" block, which allows declaring a requirement without
|
||||||
|
// also creating a configuration.
|
||||||
|
for fullName, constraints := range module.ProviderRequirements {
|
||||||
|
inst := moduledeps.ProviderInstance(fullName)
|
||||||
|
|
||||||
|
// The handling here is a bit fiddly because the moduledeps package
|
||||||
|
// was designed around the legacy (pre-0.12) configuration model
|
||||||
|
// and hasn't yet been revised to handle the new model. As a result,
|
||||||
|
// we need to do some translation here.
|
||||||
|
// FIXME: Eventually we should adjust the underlying model so we
|
||||||
|
// can also retain the source location of each constraint, for
|
||||||
|
// more informative output from the "terraform providers" command.
|
||||||
|
var rawConstraints version.Constraints
|
||||||
|
for _, constraint := range constraints {
|
||||||
|
rawConstraints = append(rawConstraints, constraint.Required...)
|
||||||
|
}
|
||||||
|
discoConstraints := discovery.NewConstraints(rawConstraints)
|
||||||
|
|
||||||
|
providers[inst] = moduledeps.ProviderDependency{
|
||||||
|
Constraints: discoConstraints,
|
||||||
|
Reason: moduledeps.ProviderDependencyExplicit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provider configurations can also include version constraints,
|
||||||
|
// allowing for more terse declaration in situations where both a
|
||||||
|
// configuration and a constraint are defined in the same module.
|
||||||
|
for fullName, pCfg := range module.ProviderConfigs {
|
||||||
|
inst := moduledeps.ProviderInstance(fullName)
|
||||||
|
discoConstraints := discovery.AllVersions
|
||||||
|
if pCfg.Version.Required != nil {
|
||||||
|
discoConstraints = discovery.NewConstraints(pCfg.Version.Required)
|
||||||
|
}
|
||||||
|
if existing, exists := providers[inst]; exists {
|
||||||
|
existing.Constraints = existing.Constraints.Append(discoConstraints)
|
||||||
|
} else {
|
||||||
|
providers[inst] = moduledeps.ProviderDependency{
|
||||||
|
Constraints: discoConstraints,
|
||||||
|
Reason: moduledeps.ProviderDependencyExplicit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each resource in the configuration creates an *implicit* provider
|
||||||
|
// dependency, though we'll only record it if there isn't already
|
||||||
|
// an explicit dependency on the same provider.
|
||||||
|
for _, rc := range module.ManagedResources {
|
||||||
|
fullName := rc.ProviderConfigKey()
|
||||||
|
inst := moduledeps.ProviderInstance(fullName)
|
||||||
|
if _, exists := providers[inst]; exists {
|
||||||
|
// Explicit dependency already present
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
reason := moduledeps.ProviderDependencyImplicit
|
||||||
|
if _, inherited := inheritProviders[fullName]; inherited {
|
||||||
|
reason = moduledeps.ProviderDependencyInherited
|
||||||
|
}
|
||||||
|
|
||||||
|
providers[inst] = moduledeps.ProviderDependency{
|
||||||
|
Constraints: discovery.AllVersions,
|
||||||
|
Reason: reason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, rc := range module.DataResources {
|
||||||
|
fullName := rc.ProviderConfigKey()
|
||||||
|
inst := moduledeps.ProviderInstance(fullName)
|
||||||
|
if _, exists := providers[inst]; exists {
|
||||||
|
// Explicit dependency already present
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
reason := moduledeps.ProviderDependencyImplicit
|
||||||
|
if _, inherited := inheritProviders[fullName]; inherited {
|
||||||
|
reason = moduledeps.ProviderDependencyInherited
|
||||||
|
}
|
||||||
|
|
||||||
|
providers[inst] = moduledeps.ProviderDependency{
|
||||||
|
Constraints: discovery.AllVersions,
|
||||||
|
Reason: reason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.Providers = providers
|
||||||
|
}
|
||||||
|
|
||||||
|
childInherit := make(map[string]*configs.Provider)
|
||||||
|
for k, v := range inheritProviders {
|
||||||
|
childInherit[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range module.ProviderConfigs {
|
||||||
|
childInherit[k] = v
|
||||||
|
}
|
||||||
|
for _, c := range root.Children {
|
||||||
|
ret.Children = append(ret.Children, configTreeConfigDependencies(c, childInherit))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func configTreeMergeStateDependencies(root *moduledeps.Module, state *State) {
|
||||||
|
if state == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
findModule := func(path []string) *moduledeps.Module {
|
||||||
|
module := root
|
||||||
|
for _, name := range path[1:] { // skip initial "root"
|
||||||
|
var next *moduledeps.Module
|
||||||
|
for _, cm := range module.Children {
|
||||||
|
if cm.Name == name {
|
||||||
|
next = cm
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if next == nil {
|
||||||
|
// If we didn't find a next node, we'll need to make one
|
||||||
|
next = &moduledeps.Module{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
module.Children = append(module.Children, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
module = next
|
||||||
|
}
|
||||||
|
return module
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ms := range state.Modules {
|
||||||
|
module := findModule(ms.Path)
|
||||||
|
|
||||||
|
for _, is := range ms.Resources {
|
||||||
|
fullName := config.ResourceProviderFullName(is.Type, is.Provider)
|
||||||
|
inst := moduledeps.ProviderInstance(fullName)
|
||||||
|
if _, exists := module.Providers[inst]; !exists {
|
||||||
|
if module.Providers == nil {
|
||||||
|
module.Providers = make(moduledeps.Providers)
|
||||||
|
}
|
||||||
|
module.Providers[inst] = moduledeps.ProviderDependency{
|
||||||
|
Constraints: discovery.AllVersions,
|
||||||
|
Reason: moduledeps.ProviderDependencyFromState,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ModuleTreeDependencies returns the dependencies of the tree of modules
|
// ModuleTreeDependencies returns the dependencies of the tree of modules
|
||||||
// described by the given configuration tree and state.
|
// described by the given configuration tree and state.
|
||||||
//
|
//
|
||||||
|
@ -106,50 +301,9 @@ func moduleTreeConfigDependencies(root *module.Tree, inheritProviders map[string
|
||||||
}
|
}
|
||||||
|
|
||||||
func moduleTreeMergeStateDependencies(root *moduledeps.Module, state *State) {
|
func moduleTreeMergeStateDependencies(root *moduledeps.Module, state *State) {
|
||||||
if state == nil {
|
// This is really just the same logic as configTreeMergeStateDependencies
|
||||||
return
|
// but we retain this old name just to keep the symmetry until we've
|
||||||
}
|
// removed all of these "moduleTree..." versions that use the legacy
|
||||||
|
// configuration structs.
|
||||||
findModule := func(path []string) *moduledeps.Module {
|
configTreeMergeStateDependencies(root, state)
|
||||||
module := root
|
|
||||||
for _, name := range path[1:] { // skip initial "root"
|
|
||||||
var next *moduledeps.Module
|
|
||||||
for _, cm := range module.Children {
|
|
||||||
if cm.Name == name {
|
|
||||||
next = cm
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if next == nil {
|
|
||||||
// If we didn't find a next node, we'll need to make one
|
|
||||||
next = &moduledeps.Module{
|
|
||||||
Name: name,
|
|
||||||
}
|
|
||||||
module.Children = append(module.Children, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
module = next
|
|
||||||
}
|
|
||||||
return module
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ms := range state.Modules {
|
|
||||||
module := findModule(ms.Path)
|
|
||||||
|
|
||||||
for _, is := range ms.Resources {
|
|
||||||
fullName := config.ResourceProviderFullName(is.Type, is.Provider)
|
|
||||||
inst := moduledeps.ProviderInstance(fullName)
|
|
||||||
if _, exists := module.Providers[inst]; !exists {
|
|
||||||
if module.Providers == nil {
|
|
||||||
module.Providers = make(moduledeps.Providers)
|
|
||||||
}
|
|
||||||
module.Providers[inst] = moduledeps.ProviderDependency{
|
|
||||||
Constraints: discovery.AllVersions,
|
|
||||||
Reason: moduledeps.ProviderDependencyFromState,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue