github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/terraform/module_dependencies.go (about)

     1  package terraform
     2  
     3  import (
     4  	"github.com/hashicorp/terraform/config"
     5  	"github.com/hashicorp/terraform/config/module"
     6  	"github.com/hashicorp/terraform/moduledeps"
     7  	"github.com/hashicorp/terraform/plugin/discovery"
     8  )
     9  
    10  // ModuleTreeDependencies returns the dependencies of the tree of modules
    11  // described by the given configuration tree and state.
    12  //
    13  // Both configuration and state are required because there can be resources
    14  // implied by instances in the state that no longer exist in config.
    15  //
    16  // This function will panic if any invalid version constraint strings are
    17  // present in the configuration. This is guaranteed not to happen for any
    18  // configuration that has passed a call to Config.Validate().
    19  func ModuleTreeDependencies(root *module.Tree, state *State) *moduledeps.Module {
    20  
    21  	// First we walk the configuration tree to build the overall structure
    22  	// and capture the explicit/implicit/inherited provider dependencies.
    23  	deps := moduleTreeConfigDependencies(root, nil)
    24  
    25  	// Next we walk over the resources in the state to catch any additional
    26  	// dependencies created by existing resources that are no longer in config.
    27  	// Most things we find in state will already be present in 'deps', but
    28  	// we're interested in the rare thing that isn't.
    29  	moduleTreeMergeStateDependencies(deps, state)
    30  
    31  	return deps
    32  }
    33  
    34  func moduleTreeConfigDependencies(root *module.Tree, inheritProviders map[string]*config.ProviderConfig) *moduledeps.Module {
    35  	if root == nil {
    36  		// If no config is provided, we'll make a synthetic root.
    37  		// This isn't necessarily correct if we're called with a nil that
    38  		// *isn't* at the root, but in practice that can never happen.
    39  		return &moduledeps.Module{
    40  			Name: "root",
    41  		}
    42  	}
    43  
    44  	ret := &moduledeps.Module{
    45  		Name: root.Name(),
    46  	}
    47  
    48  	cfg := root.Config()
    49  	providerConfigs := cfg.ProviderConfigsByFullName()
    50  
    51  	// Provider dependencies
    52  	{
    53  		providers := make(moduledeps.Providers, len(providerConfigs))
    54  
    55  		// Any providerConfigs elements are *explicit* provider dependencies,
    56  		// which is the only situation where the user might provide an actual
    57  		// version constraint. We'll take care of these first.
    58  		for fullName, pCfg := range providerConfigs {
    59  			inst := moduledeps.ProviderInstance(fullName)
    60  			versionSet := discovery.AllVersions
    61  			if pCfg.Version != "" {
    62  				versionSet = discovery.ConstraintStr(pCfg.Version).MustParse()
    63  			}
    64  			providers[inst] = moduledeps.ProviderDependency{
    65  				Constraints: versionSet,
    66  				Reason:      moduledeps.ProviderDependencyExplicit,
    67  			}
    68  		}
    69  
    70  		// Each resource in the configuration creates an *implicit* provider
    71  		// dependency, though we'll only record it if there isn't already
    72  		// an explicit dependency on the same provider.
    73  		for _, rc := range cfg.Resources {
    74  			fullName := rc.ProviderFullName()
    75  			inst := moduledeps.ProviderInstance(fullName)
    76  			if _, exists := providers[inst]; exists {
    77  				// Explicit dependency already present
    78  				continue
    79  			}
    80  
    81  			reason := moduledeps.ProviderDependencyImplicit
    82  			if _, inherited := inheritProviders[fullName]; inherited {
    83  				reason = moduledeps.ProviderDependencyInherited
    84  			}
    85  
    86  			providers[inst] = moduledeps.ProviderDependency{
    87  				Constraints: discovery.AllVersions,
    88  				Reason:      reason,
    89  			}
    90  		}
    91  
    92  		ret.Providers = providers
    93  	}
    94  
    95  	childInherit := make(map[string]*config.ProviderConfig)
    96  	for k, v := range inheritProviders {
    97  		childInherit[k] = v
    98  	}
    99  	for k, v := range providerConfigs {
   100  		childInherit[k] = v
   101  	}
   102  	for _, c := range root.Children() {
   103  		ret.Children = append(ret.Children, moduleTreeConfigDependencies(c, childInherit))
   104  	}
   105  
   106  	return ret
   107  }
   108  
   109  func moduleTreeMergeStateDependencies(root *moduledeps.Module, state *State) {
   110  	if state == nil {
   111  		return
   112  	}
   113  
   114  	findModule := func(path []string) *moduledeps.Module {
   115  		module := root
   116  		for _, name := range path[1:] { // skip initial "root"
   117  			var next *moduledeps.Module
   118  			for _, cm := range module.Children {
   119  				if cm.Name == name {
   120  					next = cm
   121  					break
   122  				}
   123  			}
   124  
   125  			if next == nil {
   126  				// If we didn't find a next node, we'll need to make one
   127  				next = &moduledeps.Module{
   128  					Name: name,
   129  				}
   130  				module.Children = append(module.Children, next)
   131  			}
   132  
   133  			module = next
   134  		}
   135  		return module
   136  	}
   137  
   138  	for _, ms := range state.Modules {
   139  		module := findModule(ms.Path)
   140  
   141  		for _, is := range ms.Resources {
   142  			fullName := config.ResourceProviderFullName(is.Type, is.Provider)
   143  			inst := moduledeps.ProviderInstance(fullName)
   144  			if _, exists := module.Providers[inst]; !exists {
   145  				if module.Providers == nil {
   146  					module.Providers = make(moduledeps.Providers)
   147  				}
   148  				module.Providers[inst] = moduledeps.ProviderDependency{
   149  					Constraints: discovery.AllVersions,
   150  					Reason:      moduledeps.ProviderDependencyFromState,
   151  				}
   152  			}
   153  		}
   154  	}
   155  
   156  }