@@ -43,18 +43,6 @@ func doYaLikeDAGs(c *Config) (*dag.AcyclicGraph, error) {
43
43
continue
44
44
}
45
45
46
- // we might not yet know if the resource is disabled, this could be due
47
- // to the value being set from a variable or an interpolated value
48
-
49
- // if disabled ignore any dependencies
50
- if resource .GetDisabled () {
51
- // add all disabled resources to the root
52
- //fmt.Println("connect", "root", "to", resource.Metadata().ID)
53
-
54
- graph .Connect (dag .BasicEdge (root , resource ))
55
- continue
56
- }
57
-
58
46
// use a map to keep a unique list
59
47
dependencies := map [types.Resource ]bool {}
60
48
@@ -87,17 +75,10 @@ func doYaLikeDAGs(c *Config) (*dag.AcyclicGraph, error) {
87
75
// then the reference should be modified to include the parent reference
88
76
// "module.module1.module2.resource.container.mine.id"
89
77
relFQDN := fqdn .AppendParentModule (resource .Metadata ().Module )
90
- deps , err := c .FindModuleResources (relFQDN .String (), true )
91
- if err != nil {
92
- pe := & errors.ParserError {}
93
- pe .Line = resource .Metadata ().Line
94
- pe .Column = resource .Metadata ().Column
95
- pe .Filename = resource .Metadata ().File
96
- pe .Message = fmt .Sprintf ("unable to find resources for module: %s, error: %s" , fqdn .Module , err )
97
- pe .Level = errors .ParserErrorLevelError
98
78
99
- return nil , pe
100
- }
79
+ // we ignore the error here as it may be possible that the module depends on
80
+ // disabled resources
81
+ deps , _ := c .FindModuleResources (relFQDN .String (), true )
101
82
102
83
for _ , dep := range deps {
103
84
dependencies [dep ] = true
@@ -112,17 +93,10 @@ func doYaLikeDAGs(c *Config) (*dag.AcyclicGraph, error) {
112
93
// then the reference should be modified to include the parent reference
113
94
// "module.module1.module2.resource.container.mine.id"
114
95
relFQDN := fqdn .AppendParentModule (resource .Metadata ().Module )
115
- dep , err := c .FindResource (relFQDN .String ())
116
- if err != nil {
117
- pe := & errors.ParserError {}
118
- pe .Line = resource .Metadata ().Line
119
- pe .Column = resource .Metadata ().Column
120
- pe .Filename = resource .Metadata ().File
121
- pe .Message = fmt .Sprintf ("unable to find dependent resource in module: '%s', error: '%s'" , resource .Metadata ().Module , err )
122
- pe .Level = errors .ParserErrorLevelError
123
96
124
- return nil , pe
125
- }
97
+ // we ignore the error here as it may be possible that the module depends on
98
+ // disabled resources
99
+ dep , _ := c .FindResource (relFQDN .String ())
126
100
127
101
dependencies [dep ] = true
128
102
}
@@ -138,7 +112,7 @@ func doYaLikeDAGs(c *Config) (*dag.AcyclicGraph, error) {
138
112
pe .Line = resource .Metadata ().Line
139
113
pe .Column = resource .Metadata ().Column
140
114
pe .Filename = resource .Metadata ().File
141
- pe .Message = fmt .Sprintf ("unable to find resources parent module: '%s, error: %s" , fqdnString , err )
115
+ pe .Message = fmt .Sprintf ("unable to find parent module: '%s' , error: %s" , fqdnString , err )
142
116
pe .Level = errors .ParserErrorLevelError
143
117
144
118
return nil , pe
@@ -178,7 +152,7 @@ func createCallback(c *Config, wf WalkCallback) func(v dag.Vertex) (diags dag.Di
178
152
}
179
153
180
154
// if this is the root module or is disabled skip or is a variable
181
- if ( r .Metadata ().Type == resources .TypeRoot ) || r . GetDisabled () {
155
+ if r .Metadata ().Type == resources .TypeRoot {
182
156
return nil
183
157
}
184
158
@@ -192,77 +166,62 @@ func createCallback(c *Config, wf WalkCallback) func(v dag.Vertex) (diags dag.Di
192
166
panic ("no context found for resource" )
193
167
}
194
168
195
- // attempt to set the values in the resource links to the resource attribute
196
- // all linked values should now have been processed as the graph
197
- // will have handled them first
198
- for _ , v := range r .Metadata ().Links {
199
- fqrn , err := resources .ParseFQRN (v )
200
- if err != nil {
201
- pe := & errors.ParserError {}
202
- pe .Filename = r .Metadata ().File
203
- pe .Line = r .Metadata ().Line
204
- pe .Column = r .Metadata ().Column
205
- pe .Message = fmt .Sprintf ("error parsing resource link %s" , err )
206
- pe .Level = errors .ParserErrorLevelError
207
-
208
- return diags .Append (pe )
209
- }
169
+ // first we need to check if the resource is disabled
170
+ // this might be set by an interpolated value
171
+ // if this is disabled we ignore the resource
172
+ //
173
+ // This expression could be a reference to another resource or it could be a
174
+ // function or a conditional statement. We need to evaluate the expression
175
+ // to determine if the resource should be disabled
176
+ if attr , ok := bdy .Attributes ["disabled" ]; ok {
177
+ expr , err := processExpr (attr .Expr )
210
178
211
- // get the value from the linked resource
212
- l , err := c .FindRelativeResource (v , r .Metadata ().Module )
179
+ // need to handle this error
213
180
if err != nil {
214
181
pe := & errors.ParserError {}
215
182
pe .Filename = r .Metadata ().File
216
183
pe .Line = r .Metadata ().Line
217
184
pe .Column = r .Metadata ().Column
218
- pe .Message = fmt .Sprintf (`unable to find dependent resource "%s" %s` , v , err )
185
+ pe .Message = fmt .Sprintf (`unable to process disabled expression: %s` , err )
219
186
pe .Level = errors .ParserErrorLevelError
220
187
221
188
return diags .Append (pe )
222
189
}
223
190
224
- var ctyRes cty.Value
225
-
226
- // once we have found a resource convert it to a cty type and then
227
- // set it on the context
228
- switch l .Metadata ().Type {
229
- case resources .TypeLocal :
230
- loc := l .(* resources.Local )
231
- ctyRes = loc .CtyValue
232
- case resources .TypeOutput :
233
- out := l .(* resources.Output )
234
- ctyRes = out .CtyValue
235
- default :
236
- ctyRes , err = convert .GoToCtyValue (l )
237
- }
238
-
239
- if err != nil {
240
- pe := & errors.ParserError {}
241
- pe .Filename = r .Metadata ().File
242
- pe .Line = r .Metadata ().Line
243
- pe .Column = r .Metadata ().Column
244
- pe .Message = fmt .Sprintf (`unable to convert reference %s to context variable: %s` , v , err )
245
- pe .Level = errors .ParserErrorLevelError
191
+ if len (expr ) > 0 {
192
+ // first we need to build the context for the expression
193
+ err := setContextVariablesFromList (c , r , expr , ctx )
194
+ if err != nil {
195
+ return diags .Append (err )
196
+ }
246
197
247
- return diags .Append (pe )
248
- }
198
+ // now we need to evaluate the expression
199
+ var isDisabled bool
200
+ expdiags := gohcl .DecodeExpression (attr .Expr , ctx , & isDisabled )
201
+ if expdiags .HasErrors () {
249
202
250
- // remove the attributes and to get a pure resource ref
251
- fqrn .Attribute = ""
203
+ pe := & errors.ParserError {}
204
+ pe .Filename = r .Metadata ().File
205
+ pe .Line = r .Metadata ().Line
206
+ pe .Column = r .Metadata ().Column
207
+ pe .Message = fmt .Sprintf (`unable to process disabled expression: %s` , expdiags .Error ())
208
+ pe .Level = errors .ParserErrorLevelError
252
209
253
- err = setContextVariableFromPath (ctx , fqrn .String (), ctyRes )
254
- if err != nil {
255
- pe := & errors.ParserError {}
256
- pe .Filename = r .Metadata ().File
257
- pe .Line = r .Metadata ().Line
258
- pe .Column = r .Metadata ().Column
259
- pe .Message = fmt .Sprintf (`unable to set context variable: %s` , err )
260
- pe .Level = errors .ParserErrorLevelError
210
+ return diags .Append (pe )
211
+ }
261
212
262
- return diags . Append ( pe )
213
+ r . SetDisabled ( isDisabled )
263
214
}
264
215
}
265
216
217
+ // if the resource is disabled we need to skip the resource
218
+ if r .GetDisabled () {
219
+ return nil
220
+ }
221
+
222
+ // set the context variables from the linked resources
223
+ setContextVariablesFromList (c , r , r .Metadata ().Links , ctx )
224
+
266
225
// Process the raw resource now we have the context from the linked
267
226
// resources
268
227
ul := getContextLock (ctx )
@@ -301,8 +260,9 @@ func createCallback(c *Config, wf WalkCallback) func(v dag.Vertex) (diags dag.Di
301
260
return diags .Append (pe )
302
261
}
303
262
304
- // if the type is a module the potentially we only just found out that we should be
263
+ // if the type is a module then potentially we only just found out that we should be
305
264
// disabled
265
+
306
266
// as an additional check, set all module resources to disabled if the module is disabled
307
267
if r .GetDisabled () && r .Metadata ().Type == resources .TypeModule {
308
268
// find all dependent resources
@@ -384,3 +344,83 @@ func createCallback(c *Config, wf WalkCallback) func(v dag.Vertex) (diags dag.Di
384
344
return nil
385
345
}
386
346
}
347
+
348
+ // setContextVariablesFromList sets the context variables from a list of resource links
349
+ //
350
+ // for example: given the values ["module.module1.module2.resource.container.mine.id"]
351
+ // the context variable "module.module1.module2.resource.container.mine.id" will be set to the
352
+ // value defined by the resource of type container with the name mine and the attribute id
353
+ func setContextVariablesFromList (c * Config , r types.Resource , values []string , ctx * hcl.EvalContext ) * errors.ParserError {
354
+ // attempt to set the values in the resource links to the resource attribute
355
+ // all linked values should now have been processed as the graph
356
+ // will have handled them first
357
+ for _ , v := range values {
358
+ fqrn , err := resources .ParseFQRN (v )
359
+ if err != nil {
360
+ pe := & errors.ParserError {}
361
+ pe .Filename = r .Metadata ().File
362
+ pe .Line = r .Metadata ().Line
363
+ pe .Column = r .Metadata ().Column
364
+ pe .Message = fmt .Sprintf ("error parsing resource link %s" , err )
365
+ pe .Level = errors .ParserErrorLevelError
366
+
367
+ return pe
368
+ }
369
+
370
+ // get the value from the linked resource
371
+ l , err := c .FindRelativeResource (v , r .Metadata ().Module )
372
+ if err != nil {
373
+ pe := & errors.ParserError {}
374
+ pe .Filename = r .Metadata ().File
375
+ pe .Line = r .Metadata ().Line
376
+ pe .Column = r .Metadata ().Column
377
+ pe .Message = fmt .Sprintf (`unable to find dependent resource "%s" %s` , v , err )
378
+ pe .Level = errors .ParserErrorLevelError
379
+
380
+ return pe
381
+ }
382
+
383
+ var ctyRes cty.Value
384
+
385
+ // once we have found a resource convert it to a cty type and then
386
+ // set it on the context
387
+ switch l .Metadata ().Type {
388
+ case resources .TypeLocal :
389
+ loc := l .(* resources.Local )
390
+ ctyRes = loc .CtyValue
391
+ case resources .TypeOutput :
392
+ out := l .(* resources.Output )
393
+ ctyRes = out .CtyValue
394
+ default :
395
+ ctyRes , err = convert .GoToCtyValue (l )
396
+ }
397
+
398
+ if err != nil {
399
+ pe := & errors.ParserError {}
400
+ pe .Filename = r .Metadata ().File
401
+ pe .Line = r .Metadata ().Line
402
+ pe .Column = r .Metadata ().Column
403
+ pe .Message = fmt .Sprintf (`unable to convert reference %s to context variable: %s` , v , err )
404
+ pe .Level = errors .ParserErrorLevelError
405
+
406
+ return pe
407
+ }
408
+
409
+ // remove the attributes and to get a pure resource ref
410
+ fqrn .Attribute = ""
411
+
412
+ err = setContextVariableFromPath (ctx , fqrn .String (), ctyRes )
413
+ if err != nil {
414
+ pe := & errors.ParserError {}
415
+ pe .Filename = r .Metadata ().File
416
+ pe .Line = r .Metadata ().Line
417
+ pe .Column = r .Metadata ().Column
418
+ pe .Message = fmt .Sprintf (`unable to set context variable: %s` , err )
419
+ pe .Level = errors .ParserErrorLevelError
420
+
421
+ return pe
422
+ }
423
+ }
424
+
425
+ return nil
426
+ }
0 commit comments