]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - terraform/module_dependencies.go
Merge branch 'fix_read_test' of github.com:alexandreFre/terraform-provider-statuscake
[github/fretlink/terraform-provider-statuscake.git] / 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 // 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 }