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 }