]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go
vendor: github.com/hashicorp/terraform/...@v0.10.0
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / module_dependencies.go
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 }