diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/shadow_components.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/terraform/shadow_components.go | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/shadow_components.go b/vendor/github.com/hashicorp/terraform/terraform/shadow_components.go new file mode 100644 index 0000000..116cf84 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/terraform/shadow_components.go | |||
@@ -0,0 +1,273 @@ | |||
1 | package terraform | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "sync" | ||
6 | |||
7 | "github.com/hashicorp/go-multierror" | ||
8 | "github.com/hashicorp/terraform/helper/shadow" | ||
9 | ) | ||
10 | |||
11 | // newShadowComponentFactory creates a shadowed contextComponentFactory | ||
12 | // so that requests to create new components result in both a real and | ||
13 | // shadow side. | ||
14 | func newShadowComponentFactory( | ||
15 | f contextComponentFactory) (contextComponentFactory, *shadowComponentFactory) { | ||
16 | // Create the shared data | ||
17 | shared := &shadowComponentFactoryShared{contextComponentFactory: f} | ||
18 | |||
19 | // Create the real side | ||
20 | real := &shadowComponentFactory{ | ||
21 | shadowComponentFactoryShared: shared, | ||
22 | } | ||
23 | |||
24 | // Create the shadow | ||
25 | shadow := &shadowComponentFactory{ | ||
26 | shadowComponentFactoryShared: shared, | ||
27 | Shadow: true, | ||
28 | } | ||
29 | |||
30 | return real, shadow | ||
31 | } | ||
32 | |||
33 | // shadowComponentFactory is the shadow side. Any components created | ||
34 | // with this factory are fake and will not cause real work to happen. | ||
35 | // | ||
36 | // Unlike other shadowers, the shadow component factory will allow the | ||
37 | // shadow to create _any_ component even if it is never requested on the | ||
38 | // real side. This is because errors will happen later downstream as function | ||
39 | // calls are made to the shadows that are never matched on the real side. | ||
40 | type shadowComponentFactory struct { | ||
41 | *shadowComponentFactoryShared | ||
42 | |||
43 | Shadow bool // True if this should return the shadow | ||
44 | lock sync.Mutex | ||
45 | } | ||
46 | |||
47 | func (f *shadowComponentFactory) ResourceProvider( | ||
48 | n, uid string) (ResourceProvider, error) { | ||
49 | f.lock.Lock() | ||
50 | defer f.lock.Unlock() | ||
51 | |||
52 | real, shadow, err := f.shadowComponentFactoryShared.ResourceProvider(n, uid) | ||
53 | var result ResourceProvider = real | ||
54 | if f.Shadow { | ||
55 | result = shadow | ||
56 | } | ||
57 | |||
58 | return result, err | ||
59 | } | ||
60 | |||
61 | func (f *shadowComponentFactory) ResourceProvisioner( | ||
62 | n, uid string) (ResourceProvisioner, error) { | ||
63 | f.lock.Lock() | ||
64 | defer f.lock.Unlock() | ||
65 | |||
66 | real, shadow, err := f.shadowComponentFactoryShared.ResourceProvisioner(n, uid) | ||
67 | var result ResourceProvisioner = real | ||
68 | if f.Shadow { | ||
69 | result = shadow | ||
70 | } | ||
71 | |||
72 | return result, err | ||
73 | } | ||
74 | |||
75 | // CloseShadow is called when the _real_ side is complete. This will cause | ||
76 | // all future blocking operations to return immediately on the shadow to | ||
77 | // ensure the shadow also completes. | ||
78 | func (f *shadowComponentFactory) CloseShadow() error { | ||
79 | // If we aren't the shadow, just return | ||
80 | if !f.Shadow { | ||
81 | return nil | ||
82 | } | ||
83 | |||
84 | // Lock ourselves so we don't modify state | ||
85 | f.lock.Lock() | ||
86 | defer f.lock.Unlock() | ||
87 | |||
88 | // Grab our shared state | ||
89 | shared := f.shadowComponentFactoryShared | ||
90 | |||
91 | // If we're already closed, its an error | ||
92 | if shared.closed { | ||
93 | return fmt.Errorf("component factory shadow already closed") | ||
94 | } | ||
95 | |||
96 | // Close all the providers and provisioners and return the error | ||
97 | var result error | ||
98 | for _, n := range shared.providerKeys { | ||
99 | _, shadow, err := shared.ResourceProvider(n, n) | ||
100 | if err == nil && shadow != nil { | ||
101 | if err := shadow.CloseShadow(); err != nil { | ||
102 | result = multierror.Append(result, err) | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | for _, n := range shared.provisionerKeys { | ||
108 | _, shadow, err := shared.ResourceProvisioner(n, n) | ||
109 | if err == nil && shadow != nil { | ||
110 | if err := shadow.CloseShadow(); err != nil { | ||
111 | result = multierror.Append(result, err) | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | // Mark ourselves as closed | ||
117 | shared.closed = true | ||
118 | |||
119 | return result | ||
120 | } | ||
121 | |||
122 | func (f *shadowComponentFactory) ShadowError() error { | ||
123 | // If we aren't the shadow, just return | ||
124 | if !f.Shadow { | ||
125 | return nil | ||
126 | } | ||
127 | |||
128 | // Lock ourselves so we don't modify state | ||
129 | f.lock.Lock() | ||
130 | defer f.lock.Unlock() | ||
131 | |||
132 | // Grab our shared state | ||
133 | shared := f.shadowComponentFactoryShared | ||
134 | |||
135 | // If we're not closed, its an error | ||
136 | if !shared.closed { | ||
137 | return fmt.Errorf("component factory must be closed to retrieve errors") | ||
138 | } | ||
139 | |||
140 | // Close all the providers and provisioners and return the error | ||
141 | var result error | ||
142 | for _, n := range shared.providerKeys { | ||
143 | _, shadow, err := shared.ResourceProvider(n, n) | ||
144 | if err == nil && shadow != nil { | ||
145 | if err := shadow.ShadowError(); err != nil { | ||
146 | result = multierror.Append(result, err) | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | for _, n := range shared.provisionerKeys { | ||
152 | _, shadow, err := shared.ResourceProvisioner(n, n) | ||
153 | if err == nil && shadow != nil { | ||
154 | if err := shadow.ShadowError(); err != nil { | ||
155 | result = multierror.Append(result, err) | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | return result | ||
161 | } | ||
162 | |||
163 | // shadowComponentFactoryShared is shared data between the two factories. | ||
164 | // | ||
165 | // It is NOT SAFE to run any function on this struct in parallel. Lock | ||
166 | // access to this struct. | ||
167 | type shadowComponentFactoryShared struct { | ||
168 | contextComponentFactory | ||
169 | |||
170 | closed bool | ||
171 | providers shadow.KeyedValue | ||
172 | providerKeys []string | ||
173 | provisioners shadow.KeyedValue | ||
174 | provisionerKeys []string | ||
175 | } | ||
176 | |||
177 | // shadowResourceProviderFactoryEntry is the entry that is stored in | ||
178 | // the Shadows key/value for a provider. | ||
179 | type shadowComponentFactoryProviderEntry struct { | ||
180 | Real ResourceProvider | ||
181 | Shadow shadowResourceProvider | ||
182 | Err error | ||
183 | } | ||
184 | |||
185 | type shadowComponentFactoryProvisionerEntry struct { | ||
186 | Real ResourceProvisioner | ||
187 | Shadow shadowResourceProvisioner | ||
188 | Err error | ||
189 | } | ||
190 | |||
191 | func (f *shadowComponentFactoryShared) ResourceProvider( | ||
192 | n, uid string) (ResourceProvider, shadowResourceProvider, error) { | ||
193 | // Determine if we already have a value | ||
194 | raw, ok := f.providers.ValueOk(uid) | ||
195 | if !ok { | ||
196 | // Build the entry | ||
197 | var entry shadowComponentFactoryProviderEntry | ||
198 | |||
199 | // No value, initialize. Create the original | ||
200 | p, err := f.contextComponentFactory.ResourceProvider(n, uid) | ||
201 | if err != nil { | ||
202 | entry.Err = err | ||
203 | p = nil // Just to be sure | ||
204 | } | ||
205 | |||
206 | if p != nil { | ||
207 | // Create the shadow | ||
208 | real, shadow := newShadowResourceProvider(p) | ||
209 | entry.Real = real | ||
210 | entry.Shadow = shadow | ||
211 | |||
212 | if f.closed { | ||
213 | shadow.CloseShadow() | ||
214 | } | ||
215 | } | ||
216 | |||
217 | // Store the value | ||
218 | f.providers.SetValue(uid, &entry) | ||
219 | f.providerKeys = append(f.providerKeys, uid) | ||
220 | raw = &entry | ||
221 | } | ||
222 | |||
223 | // Read the entry | ||
224 | entry, ok := raw.(*shadowComponentFactoryProviderEntry) | ||
225 | if !ok { | ||
226 | return nil, nil, fmt.Errorf("Unknown value for shadow provider: %#v", raw) | ||
227 | } | ||
228 | |||
229 | // Return | ||
230 | return entry.Real, entry.Shadow, entry.Err | ||
231 | } | ||
232 | |||
233 | func (f *shadowComponentFactoryShared) ResourceProvisioner( | ||
234 | n, uid string) (ResourceProvisioner, shadowResourceProvisioner, error) { | ||
235 | // Determine if we already have a value | ||
236 | raw, ok := f.provisioners.ValueOk(uid) | ||
237 | if !ok { | ||
238 | // Build the entry | ||
239 | var entry shadowComponentFactoryProvisionerEntry | ||
240 | |||
241 | // No value, initialize. Create the original | ||
242 | p, err := f.contextComponentFactory.ResourceProvisioner(n, uid) | ||
243 | if err != nil { | ||
244 | entry.Err = err | ||
245 | p = nil // Just to be sure | ||
246 | } | ||
247 | |||
248 | if p != nil { | ||
249 | // For now, just create a mock since we don't support provisioners yet | ||
250 | real, shadow := newShadowResourceProvisioner(p) | ||
251 | entry.Real = real | ||
252 | entry.Shadow = shadow | ||
253 | |||
254 | if f.closed { | ||
255 | shadow.CloseShadow() | ||
256 | } | ||
257 | } | ||
258 | |||
259 | // Store the value | ||
260 | f.provisioners.SetValue(uid, &entry) | ||
261 | f.provisionerKeys = append(f.provisionerKeys, uid) | ||
262 | raw = &entry | ||
263 | } | ||
264 | |||
265 | // Read the entry | ||
266 | entry, ok := raw.(*shadowComponentFactoryProvisionerEntry) | ||
267 | if !ok { | ||
268 | return nil, nil, fmt.Errorf("Unknown value for shadow provisioner: %#v", raw) | ||
269 | } | ||
270 | |||
271 | // Return | ||
272 | return entry.Real, entry.Shadow, entry.Err | ||
273 | } | ||