]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/hashicorp/terraform/terraform/module_dependencies.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / module_dependencies.go
CommitLineData
c680a8e1
RS
1package terraform
2
3import (
107c1cdb
ND
4 version "github.com/hashicorp/go-version"
5
6 "github.com/hashicorp/terraform/addrs"
7 "github.com/hashicorp/terraform/configs"
c680a8e1
RS
8 "github.com/hashicorp/terraform/moduledeps"
9 "github.com/hashicorp/terraform/plugin/discovery"
107c1cdb 10 "github.com/hashicorp/terraform/states"
c680a8e1
RS
11)
12
107c1cdb
ND
13// ConfigTreeDependencies returns the dependencies of the tree of modules
14// described by the given configuration and state.
c680a8e1
RS
15//
16// Both configuration and state are required because there can be resources
17// implied by instances in the state that no longer exist in config.
107c1cdb 18func ConfigTreeDependencies(root *configs.Config, state *states.State) *moduledeps.Module {
c680a8e1
RS
19 // First we walk the configuration tree to build the overall structure
20 // and capture the explicit/implicit/inherited provider dependencies.
107c1cdb 21 deps := configTreeConfigDependencies(root, nil)
c680a8e1
RS
22
23 // Next we walk over the resources in the state to catch any additional
24 // dependencies created by existing resources that are no longer in config.
25 // Most things we find in state will already be present in 'deps', but
26 // we're interested in the rare thing that isn't.
107c1cdb 27 configTreeMergeStateDependencies(deps, state)
c680a8e1
RS
28
29 return deps
30}
31
107c1cdb 32func configTreeConfigDependencies(root *configs.Config, inheritProviders map[string]*configs.Provider) *moduledeps.Module {
c680a8e1
RS
33 if root == nil {
34 // If no config is provided, we'll make a synthetic root.
35 // This isn't necessarily correct if we're called with a nil that
36 // *isn't* at the root, but in practice that can never happen.
37 return &moduledeps.Module{
107c1cdb
ND
38 Name: "root",
39 Providers: make(moduledeps.Providers),
c680a8e1
RS
40 }
41 }
42
107c1cdb
ND
43 name := "root"
44 if len(root.Path) != 0 {
45 name = root.Path[len(root.Path)-1]
46 }
47
c680a8e1 48 ret := &moduledeps.Module{
107c1cdb 49 Name: name,
c680a8e1
RS
50 }
51
107c1cdb 52 module := root.Module
c680a8e1
RS
53
54 // Provider dependencies
55 {
107c1cdb 56 providers := make(moduledeps.Providers)
c680a8e1 57
107c1cdb
ND
58 // The main way to declare a provider dependency is explicitly inside
59 // the "terraform" block, which allows declaring a requirement without
60 // also creating a configuration.
61 for fullName, constraints := range module.ProviderRequirements {
c680a8e1 62 inst := moduledeps.ProviderInstance(fullName)
107c1cdb
ND
63
64 // The handling here is a bit fiddly because the moduledeps package
65 // was designed around the legacy (pre-0.12) configuration model
66 // and hasn't yet been revised to handle the new model. As a result,
67 // we need to do some translation here.
68 // FIXME: Eventually we should adjust the underlying model so we
69 // can also retain the source location of each constraint, for
70 // more informative output from the "terraform providers" command.
71 var rawConstraints version.Constraints
72 for _, constraint := range constraints {
73 rawConstraints = append(rawConstraints, constraint.Required...)
c680a8e1 74 }
107c1cdb
ND
75 discoConstraints := discovery.NewConstraints(rawConstraints)
76
c680a8e1 77 providers[inst] = moduledeps.ProviderDependency{
107c1cdb 78 Constraints: discoConstraints,
c680a8e1
RS
79 Reason: moduledeps.ProviderDependencyExplicit,
80 }
81 }
82
107c1cdb
ND
83 // Provider configurations can also include version constraints,
84 // allowing for more terse declaration in situations where both a
85 // configuration and a constraint are defined in the same module.
86 for fullName, pCfg := range module.ProviderConfigs {
87 inst := moduledeps.ProviderInstance(fullName)
88 discoConstraints := discovery.AllVersions
89 if pCfg.Version.Required != nil {
90 discoConstraints = discovery.NewConstraints(pCfg.Version.Required)
91 }
92 if existing, exists := providers[inst]; exists {
93 existing.Constraints = existing.Constraints.Append(discoConstraints)
94 } else {
95 providers[inst] = moduledeps.ProviderDependency{
96 Constraints: discoConstraints,
97 Reason: moduledeps.ProviderDependencyExplicit,
98 }
99 }
100 }
101
c680a8e1
RS
102 // Each resource in the configuration creates an *implicit* provider
103 // dependency, though we'll only record it if there isn't already
104 // an explicit dependency on the same provider.
107c1cdb
ND
105 for _, rc := range module.ManagedResources {
106 addr := rc.ProviderConfigAddr()
107 inst := moduledeps.ProviderInstance(addr.StringCompact())
108 if _, exists := providers[inst]; exists {
109 // Explicit dependency already present
110 continue
111 }
112
113 reason := moduledeps.ProviderDependencyImplicit
114 if _, inherited := inheritProviders[addr.StringCompact()]; inherited {
115 reason = moduledeps.ProviderDependencyInherited
116 }
117
118 providers[inst] = moduledeps.ProviderDependency{
119 Constraints: discovery.AllVersions,
120 Reason: reason,
121 }
122 }
123 for _, rc := range module.DataResources {
124 addr := rc.ProviderConfigAddr()
125 inst := moduledeps.ProviderInstance(addr.StringCompact())
c680a8e1
RS
126 if _, exists := providers[inst]; exists {
127 // Explicit dependency already present
128 continue
129 }
130
131 reason := moduledeps.ProviderDependencyImplicit
107c1cdb 132 if _, inherited := inheritProviders[addr.String()]; inherited {
c680a8e1
RS
133 reason = moduledeps.ProviderDependencyInherited
134 }
135
136 providers[inst] = moduledeps.ProviderDependency{
137 Constraints: discovery.AllVersions,
138 Reason: reason,
139 }
140 }
141
142 ret.Providers = providers
143 }
144
107c1cdb 145 childInherit := make(map[string]*configs.Provider)
c680a8e1
RS
146 for k, v := range inheritProviders {
147 childInherit[k] = v
148 }
107c1cdb 149 for k, v := range module.ProviderConfigs {
c680a8e1
RS
150 childInherit[k] = v
151 }
107c1cdb
ND
152 for _, c := range root.Children {
153 ret.Children = append(ret.Children, configTreeConfigDependencies(c, childInherit))
c680a8e1
RS
154 }
155
156 return ret
157}
158
107c1cdb 159func configTreeMergeStateDependencies(root *moduledeps.Module, state *states.State) {
c680a8e1
RS
160 if state == nil {
161 return
162 }
163
107c1cdb 164 findModule := func(path addrs.ModuleInstance) *moduledeps.Module {
c680a8e1 165 module := root
107c1cdb 166 for _, step := range path {
c680a8e1
RS
167 var next *moduledeps.Module
168 for _, cm := range module.Children {
107c1cdb 169 if cm.Name == step.Name {
c680a8e1
RS
170 next = cm
171 break
172 }
173 }
174
175 if next == nil {
176 // If we didn't find a next node, we'll need to make one
177 next = &moduledeps.Module{
107c1cdb
ND
178 Name: step.Name,
179 Providers: make(moduledeps.Providers),
c680a8e1
RS
180 }
181 module.Children = append(module.Children, next)
182 }
183
184 module = next
185 }
186 return module
187 }
188
189 for _, ms := range state.Modules {
107c1cdb 190 module := findModule(ms.Addr)
c680a8e1 191
107c1cdb
ND
192 for _, rs := range ms.Resources {
193 inst := moduledeps.ProviderInstance(rs.ProviderConfig.ProviderConfig.StringCompact())
c680a8e1 194 if _, exists := module.Providers[inst]; !exists {
c680a8e1
RS
195 module.Providers[inst] = moduledeps.ProviderDependency{
196 Constraints: discovery.AllVersions,
197 Reason: moduledeps.ProviderDependencyFromState,
198 }
199 }
200 }
201 }
c680a8e1 202}