forked from hashicorp/terraform
/
transform_config.go
135 lines (110 loc) · 3.15 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
134
135
package terraform
import (
"errors"
"fmt"
"log"
"sync"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
"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.
Module *module.Tree
// 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 config.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 module is given, we don't do anything
if t.Module == nil {
return nil
}
// If the module isn't loaded, that is simply an error
if !t.Module.Loaded() {
return errors.New("module must be loaded for ConfigTransformer")
}
// 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.Module)
}
func (t *ConfigTransformer) transform(g *Graph, m *module.Tree) error {
// If no config, do nothing
if m == nil {
return nil
}
// Add our resources
if err := t.transformSingle(g, m); err != nil {
return err
}
// Transform all the children.
for _, c := range m.Children() {
if err := t.transform(g, c); err != nil {
return err
}
}
return nil
}
func (t *ConfigTransformer) transformSingle(g *Graph, m *module.Tree) error {
log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", m.Path())
// Get the configuration for this module
conf := m.Config()
// Build the path we're at
path := m.Path()
// Write all the resources out
for _, r := range conf.Resources {
// Build the resource address
addr, err := parseResourceAddressConfig(r)
if err != nil {
panic(fmt.Sprintf(
"Error parsing config address, this is a bug: %#v", r))
}
addr.Path = path
// If this is already in our uniqueness map, don't add it again
if _, ok := t.uniqueMap[addr.String()]; ok {
continue
}
// Remove non-matching modes
if t.ModeFilter && addr.Mode != t.Mode {
continue
}
// Build the abstract node and the concrete one
abstract := &NodeAbstractResource{Addr: addr}
var node dag.Vertex = abstract
if f := t.Concrete; f != nil {
node = f(abstract)
}
// Add it to the graph
g.Add(node)
}
return nil
}