/
transform_config.go
133 lines (109 loc) · 3.44 KB
/
transform_config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package terraform
import (
"log"
"sync"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/dag"
)
// ConfigTransformer is a GraphTransformer that adds all the resources
// from the configuration to the graph.
//
// The module used to configure this transformer must be the root module.
//
// Only resources are added to the graph. Variables, outputs, and
// providers must be added via other transforms.
//
// Unlike ConfigTransformerOld, this transformer creates a graph with
// all resources including module resources, rather than creating module
// nodes that are then "flattened".
type ConfigTransformer struct {
Concrete ConcreteResourceNodeFunc
// Module is the module to add resources from.
Config *configs.Config
// Unique will only add resources that aren't already present in the graph.
Unique bool
// Mode will only add resources that match the given mode
ModeFilter bool
Mode addrs.ResourceMode
l sync.Mutex
uniqueMap map[string]struct{}
}
func (t *ConfigTransformer) Transform(g *Graph) error {
// Lock since we use some internal state
t.l.Lock()
defer t.l.Unlock()
// If no configuration is available, we don't do anything
if t.Config == nil {
return nil
}
// Reset the uniqueness map. If we're tracking uniques, then populate
// it with addresses.
t.uniqueMap = make(map[string]struct{})
defer func() { t.uniqueMap = nil }()
if t.Unique {
for _, v := range g.Vertices() {
if rn, ok := v.(GraphNodeResource); ok {
t.uniqueMap[rn.ResourceAddr().String()] = struct{}{}
}
}
}
// Start the transformation process
return t.transform(g, t.Config)
}
func (t *ConfigTransformer) transform(g *Graph, config *configs.Config) error {
// If no config, do nothing
if config == nil {
return nil
}
// Add our resources
if err := t.transformSingle(g, config); err != nil {
return err
}
// Transform all the children.
for _, c := range config.Children {
if err := t.transform(g, c); err != nil {
return err
}
}
return nil
}
func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) error {
path := config.Path
module := config.Module
log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path)
// For now we assume that each module call produces only one module
// instance with no key, since we don't yet support "count" and "for_each"
// on modules.
// FIXME: As part of supporting "count" and "for_each" on modules, rework
// this so that we'll "expand" the module call first and then create graph
// nodes for each module instance separately.
instPath := path.UnkeyedInstanceShim()
allResources := make([]*configs.Resource, 0, len(module.ManagedResources)+len(module.DataResources))
for _, r := range module.ManagedResources {
allResources = append(allResources, r)
}
for _, r := range module.DataResources {
allResources = append(allResources, r)
}
for _, r := range allResources {
relAddr := r.Addr()
if t.ModeFilter && relAddr.Mode != t.Mode {
// Skip non-matching modes
continue
}
addr := relAddr.Absolute(instPath)
if _, ok := t.uniqueMap[addr.String()]; ok {
// We've already seen a resource with this address. This should
// never happen, because we enforce uniqueness in the config loader.
continue
}
abstract := &NodeAbstractResource{Addr: addr}
var node dag.Vertex = abstract
if f := t.Concrete; f != nil {
node = f(abstract)
}
g.Add(node)
}
return nil
}