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