@ -1,36 +1,34 @@
package terraform
import (
version "github.com/hashicorp/go-version"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/moduledeps"
"github.com/hashicorp/terraform/plugin/discovery"
)
// Module TreeDependencies returns the dependencies of the tree of modules
// described by the given configuration tree and state.
// Config TreeDependencies 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.
//
// This function will panic if any invalid version constraint strings are
// present in the configuration. This is guaranteed not to happen for any
// configuration that has passed a call to Config.Validate().
func ModuleTreeDependencies ( root * module . Tree , state * State ) * moduledeps . Module {
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 := module TreeConfigDependencies( root , nil )
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.
module TreeMergeStateDependencies( deps , state )
config TreeMergeStateDependencies( deps , state )
return deps
}
func moduleTreeConfigDependencies( root * module . Tree , inheritProviders map [ string ] * config . Provider Config ) * moduledeps . Module {
func configTreeConfigDependencies( root * configs . Config , inheritProviders map [ string ] * config s . 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
@ -40,37 +38,88 @@ func moduleTreeConfigDependencies(root *module.Tree, inheritProviders map[string
}
}
name := "root"
if len ( root . Path ) != 0 {
name = root . Path [ len ( root . Path ) - 1 ]
}
ret := & moduledeps . Module {
Name : root . Name ( ) ,
Name : name ,
}
cfg := root . Config ( )
providerConfigs := cfg . ProviderConfigsByFullName ( )
module := root . Module
// Provider dependencies
{
providers := make ( moduledeps . Providers , len ( providerConfigs ) )
providers := make ( moduledeps . Providers )
// Any providerConfigs elements are *explicit* provider dependencies,
// which is the only situation where the user might provide an actual
// version constraint. We'll take care of these first .
for fullName , pCfg := range providerConfig s {
// 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 . ProviderRequirement s {
inst := moduledeps . ProviderInstance ( fullName )
versionSet := discovery . AllVersions
if pCfg . Version != "" {
versionSet = discovery . ConstraintStr ( pCfg . Version ) . MustParse ( )
// 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 : versionSet ,
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 cfg . Resources {
fullName := rc . ProviderFullName ( )
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
@ -91,21 +140,21 @@ func moduleTreeConfigDependencies(root *module.Tree, inheritProviders map[string
ret . Providers = providers
}
childInherit := make ( map [ string ] * config . Provider Config )
childInherit := make ( map [ string ] * config s . Provider )
for k , v := range inheritProviders {
childInherit [ k ] = v
}
for k , v := range p roviderConfigs {
for k , v := range module. P roviderConfigs {
childInherit [ k ] = v
}
for _ , c := range root . Children ( ) {
ret . Children = append ( ret . Children , module TreeConfigDependencies( c , childInherit ) )
for _ , c := range root . Children {
ret . Children = append ( ret . Children , config TreeConfigDependencies( c , childInherit ) )
}
return ret
}
func module TreeMergeStateDependencies( root * moduledeps . Module , state * State ) {
func config TreeMergeStateDependencies( root * moduledeps . Module , state * State ) {
if state == nil {
return
}
@ -151,5 +200,110 @@ func moduleTreeMergeStateDependencies(root *moduledeps.Module, state *State) {
}
}
}
}
// ModuleTreeDependencies returns the dependencies of the tree of modules
// described by the given configuration tree 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.
//
// This function will panic if any invalid version constraint strings are
// present in the configuration. This is guaranteed not to happen for any
// configuration that has passed a call to Config.Validate().
func ModuleTreeDependencies ( root * module . Tree , state * State ) * moduledeps . Module {
// First we walk the configuration tree to build the overall structure
// and capture the explicit/implicit/inherited provider dependencies.
deps := moduleTreeConfigDependencies ( 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.
moduleTreeMergeStateDependencies ( deps , state )
return deps
}
func moduleTreeConfigDependencies ( root * module . Tree , inheritProviders map [ string ] * config . ProviderConfig ) * 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" ,
}
}
ret := & moduledeps . Module {
Name : root . Name ( ) ,
}
cfg := root . Config ( )
providerConfigs := cfg . ProviderConfigsByFullName ( )
// Provider dependencies
{
providers := make ( moduledeps . Providers , len ( providerConfigs ) )
// Any providerConfigs elements are *explicit* provider dependencies,
// which is the only situation where the user might provide an actual
// version constraint. We'll take care of these first.
for fullName , pCfg := range providerConfigs {
inst := moduledeps . ProviderInstance ( fullName )
versionSet := discovery . AllVersions
if pCfg . Version != "" {
versionSet = discovery . ConstraintStr ( pCfg . Version ) . MustParse ( )
}
providers [ inst ] = moduledeps . ProviderDependency {
Constraints : versionSet ,
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 cfg . Resources {
fullName := rc . ProviderFullName ( )
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 ] * config . ProviderConfig )
for k , v := range inheritProviders {
childInherit [ k ] = v
}
for k , v := range providerConfigs {
childInherit [ k ] = v
}
for _ , c := range root . Children ( ) {
ret . Children = append ( ret . Children , moduleTreeConfigDependencies ( c , childInherit ) )
}
return ret
}
func moduleTreeMergeStateDependencies ( root * moduledeps . Module , state * State ) {
// This is really just the same logic as configTreeMergeStateDependencies
// 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.
configTreeMergeStateDependencies ( root , state )
}