github.com/johandry/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 }