Skip to content

Commit 1ee851f

Browse files
authored
Merge pull request #22846 from hashicorp/jbardin/evaluate-resource
Always evaluate resources in their entirety
2 parents d6983ea + bfce780 commit 1ee851f

File tree

11 files changed

+201
-249
lines changed

11 files changed

+201
-249
lines changed

addrs/parse_ref.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ func parseResourceRef(mode ResourceMode, startRange hcl.Range, traversal hcl.Tra
290290
// of the resource, but we don't have enough context here to decide
291291
// so we'll let the caller resolve that ambiguity.
292292
return &Reference{
293-
Subject: resourceInstAddr,
293+
Subject: resourceAddr,
294294
SourceRange: tfdiags.SourceRangeFromHCL(rng),
295295
}, diags
296296
}

addrs/parse_ref_test.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,10 @@ func TestParseRef(t *testing.T) {
114114
{
115115
`data.external.foo`,
116116
&Reference{
117-
Subject: ResourceInstance{
118-
Resource: Resource{
119-
Mode: DataResourceMode,
120-
Type: "external",
121-
Name: "foo",
122-
},
117+
Subject: Resource{
118+
Mode: DataResourceMode,
119+
Type: "external",
120+
Name: "foo",
123121
},
124122
SourceRange: tfdiags.SourceRange{
125123
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
@@ -592,12 +590,10 @@ func TestParseRef(t *testing.T) {
592590
{
593591
`boop_instance.foo`,
594592
&Reference{
595-
Subject: ResourceInstance{
596-
Resource: Resource{
597-
Mode: ManagedResourceMode,
598-
Type: "boop_instance",
599-
Name: "foo",
600-
},
593+
Subject: Resource{
594+
Mode: ManagedResourceMode,
595+
Type: "boop_instance",
596+
Name: "foo",
601597
},
602598
SourceRange: tfdiags.SourceRange{
603599
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},

configs/configupgrade/analysis_expr.go

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,28 +75,27 @@ func (d analysisData) GetForEachAttr(addr addrs.ForEachAttr, rng tfdiags.SourceR
7575
return cty.DynamicVal, nil
7676
}
7777

78-
func (d analysisData) GetResourceInstance(instAddr addrs.ResourceInstance, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
79-
log.Printf("[TRACE] configupgrade: Determining type for %s", instAddr)
80-
addr := instAddr.Resource
78+
func (d analysisData) GetResource(addr addrs.Resource, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
79+
log.Printf("[TRACE] configupgrade: Determining type for %s", addr)
8180

8281
// Our analysis pass should've found a suitable schema for every resource
8382
// type in the module.
8483
providerType, ok := d.an.ResourceProviderType[addr]
8584
if !ok {
8685
// Should not be possible, since analysis visits every resource block.
87-
log.Printf("[TRACE] configupgrade: analysis.GetResourceInstance doesn't have a provider type for %s", addr)
86+
log.Printf("[TRACE] configupgrade: analysis.GetResource doesn't have a provider type for %s", addr)
8887
return cty.DynamicVal, nil
8988
}
9089
providerSchema, ok := d.an.ProviderSchemas[providerType]
9190
if !ok {
9291
// Should not be possible, since analysis loads schema for every provider.
93-
log.Printf("[TRACE] configupgrade: analysis.GetResourceInstance doesn't have a provider schema for for %q", providerType)
92+
log.Printf("[TRACE] configupgrade: analysis.GetResource doesn't have a provider schema for for %q", providerType)
9493
return cty.DynamicVal, nil
9594
}
9695
schema, _ := providerSchema.SchemaForResourceAddr(addr)
9796
if schema == nil {
9897
// Should not be possible, since analysis loads schema for every provider.
99-
log.Printf("[TRACE] configupgrade: analysis.GetResourceInstance doesn't have a schema for for %s", addr)
98+
log.Printf("[TRACE] configupgrade: analysis.GetResource doesn't have a schema for for %s", addr)
10099
return cty.DynamicVal, nil
101100
}
102101

@@ -106,19 +105,11 @@ func (d analysisData) GetResourceInstance(instAddr addrs.ResourceInstance, rng t
106105
// return a list or a single object type depending on whether count is
107106
// set and whether an instance key is given in the address.
108107
if d.an.ResourceHasCount[addr] {
109-
if instAddr.Key == addrs.NoKey {
110-
log.Printf("[TRACE] configupgrade: %s refers to counted instance without a key, so result is a list of %#v", instAddr, objTy)
111-
return cty.UnknownVal(cty.List(objTy)), nil
112-
}
113-
log.Printf("[TRACE] configupgrade: %s refers to counted instance with a key, so result is single object", instAddr)
114-
return cty.UnknownVal(objTy), nil
108+
log.Printf("[TRACE] configupgrade: %s refers to counted instance, so result is a list of %#v", addr, objTy)
109+
return cty.UnknownVal(cty.List(objTy)), nil
115110
}
116111

117-
if instAddr.Key != addrs.NoKey {
118-
log.Printf("[TRACE] configupgrade: %s refers to non-counted instance with a key, which is invalid", instAddr)
119-
return cty.DynamicVal, nil
120-
}
121-
log.Printf("[TRACE] configupgrade: %s refers to non-counted instance without a key, so result is single object", instAddr)
112+
log.Printf("[TRACE] configupgrade: %s refers to non-counted instance, so result is single object", addr)
122113
return cty.UnknownVal(objTy), nil
123114
}
124115

lang/data.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type Data interface {
2424

2525
GetCountAttr(addrs.CountAttr, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
2626
GetForEachAttr(addrs.ForEachAttr, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
27-
GetResourceInstance(addrs.ResourceInstance, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
27+
GetResource(addrs.Resource, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
2828
GetLocalValue(addrs.LocalValue, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
2929
GetModuleInstance(addrs.ModuleCallInstance, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
3030
GetModuleInstanceOutput(addrs.ModuleCallOutput, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)

lang/data_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import (
77
)
88

99
type dataForTests struct {
10-
CountAttrs map[string]cty.Value
11-
ForEachAttrs map[string]cty.Value
12-
ResourceInstances map[string]cty.Value
13-
LocalValues map[string]cty.Value
14-
Modules map[string]cty.Value
15-
PathAttrs map[string]cty.Value
16-
TerraformAttrs map[string]cty.Value
17-
InputVariables map[string]cty.Value
10+
CountAttrs map[string]cty.Value
11+
ForEachAttrs map[string]cty.Value
12+
Resources map[string]cty.Value
13+
LocalValues map[string]cty.Value
14+
Modules map[string]cty.Value
15+
PathAttrs map[string]cty.Value
16+
TerraformAttrs map[string]cty.Value
17+
InputVariables map[string]cty.Value
1818
}
1919

2020
var _ Data = &dataForTests{}
@@ -31,8 +31,8 @@ func (d *dataForTests) GetForEachAttr(addr addrs.ForEachAttr, rng tfdiags.Source
3131
return d.ForEachAttrs[addr.Name], nil
3232
}
3333

34-
func (d *dataForTests) GetResourceInstance(addr addrs.ResourceInstance, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
35-
return d.ResourceInstances[addr.String()], nil
34+
func (d *dataForTests) GetResource(addr addrs.Resource, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
35+
return d.Resources[addr.String()], nil
3636
}
3737

3838
func (d *dataForTests) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {

lang/eval.go

Lines changed: 40 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
194194
// it, since that allows us to gather a full set of any errors and
195195
// warnings, but once we've gathered all the data we'll then skip anything
196196
// that's redundant in the process of populating our values map.
197-
dataResources := map[string]map[string]map[addrs.InstanceKey]cty.Value{}
198-
managedResources := map[string]map[string]map[addrs.InstanceKey]cty.Value{}
197+
dataResources := map[string]map[string]cty.Value{}
198+
managedResources := map[string]map[string]cty.Value{}
199199
wholeModules := map[string]map[addrs.InstanceKey]cty.Value{}
200200
moduleOutputs := map[string]map[addrs.InstanceKey]map[string]cty.Value{}
201201
inputVariables := map[string]cty.Value{}
@@ -208,7 +208,6 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
208208

209209
for _, ref := range refs {
210210
rng := ref.SourceRange
211-
isSelf := false
212211

213212
rawSubj := ref.Subject
214213
if rawSubj == addrs.Self {
@@ -226,45 +225,60 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
226225
continue
227226
}
228227

229-
// Treat "self" as an alias for the configured self address.
230-
rawSubj = selfAddr
231-
isSelf = true
232-
233-
if rawSubj == addrs.Self {
228+
if selfAddr == addrs.Self {
234229
// Programming error: the self address cannot alias itself.
235230
panic("scope SelfAddr attempting to alias itself")
236231
}
232+
233+
// self can only be used within a resource instance
234+
subj := selfAddr.(addrs.ResourceInstance)
235+
236+
val, valDiags := normalizeRefValue(s.Data.GetResource(subj.ContainingResource(), rng))
237+
238+
diags = diags.Append(valDiags)
239+
240+
// Self is an exception in that it must always resolve to a
241+
// particular instance. We will still insert the full resource into
242+
// the context below.
243+
switch k := subj.Key.(type) {
244+
case addrs.IntKey:
245+
self = val.Index(cty.NumberIntVal(int64(k)))
246+
case addrs.StringKey:
247+
self = val.Index(cty.StringVal(string(k)))
248+
default:
249+
self = val
250+
}
251+
252+
continue
237253
}
238254

239255
// This type switch must cover all of the "Referenceable" implementations
240-
// in package addrs.
241-
switch subj := rawSubj.(type) {
256+
// in package addrs, however we are removing the possibility of
257+
// ResourceInstance beforehand.
258+
if addr, ok := rawSubj.(addrs.ResourceInstance); ok {
259+
rawSubj = addr.ContainingResource()
260+
}
242261

243-
case addrs.ResourceInstance:
244-
var into map[string]map[string]map[addrs.InstanceKey]cty.Value
245-
switch subj.Resource.Mode {
262+
switch subj := rawSubj.(type) {
263+
case addrs.Resource:
264+
var into map[string]map[string]cty.Value
265+
switch subj.Mode {
246266
case addrs.ManagedResourceMode:
247267
into = managedResources
248268
case addrs.DataResourceMode:
249269
into = dataResources
250270
default:
251-
panic(fmt.Errorf("unsupported ResourceMode %s", subj.Resource.Mode))
271+
panic(fmt.Errorf("unsupported ResourceMode %s", subj.Mode))
252272
}
253273

254-
val, valDiags := normalizeRefValue(s.Data.GetResourceInstance(subj, rng))
274+
val, valDiags := normalizeRefValue(s.Data.GetResource(subj, rng))
255275
diags = diags.Append(valDiags)
256276

257-
r := subj.Resource
277+
r := subj
258278
if into[r.Type] == nil {
259-
into[r.Type] = make(map[string]map[addrs.InstanceKey]cty.Value)
260-
}
261-
if into[r.Type][r.Name] == nil {
262-
into[r.Type][r.Name] = make(map[addrs.InstanceKey]cty.Value)
263-
}
264-
into[r.Type][r.Name][subj.Key] = val
265-
if isSelf {
266-
self = val
279+
into[r.Type] = make(map[string]cty.Value)
267280
}
281+
into[r.Type][r.Name] = val
268282

269283
case addrs.ModuleCallInstance:
270284
val, valDiags := normalizeRefValue(s.Data.GetModuleInstance(subj, rng))
@@ -274,9 +288,6 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
274288
wholeModules[subj.Call.Name] = make(map[addrs.InstanceKey]cty.Value)
275289
}
276290
wholeModules[subj.Call.Name][subj.Key] = val
277-
if isSelf {
278-
self = val
279-
}
280291

281292
case addrs.ModuleCallOutput:
282293
val, valDiags := normalizeRefValue(s.Data.GetModuleInstanceOutput(subj, rng))
@@ -291,57 +302,36 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
291302
moduleOutputs[callName][callKey] = make(map[string]cty.Value)
292303
}
293304
moduleOutputs[callName][callKey][subj.Name] = val
294-
if isSelf {
295-
self = val
296-
}
297305

298306
case addrs.InputVariable:
299307
val, valDiags := normalizeRefValue(s.Data.GetInputVariable(subj, rng))
300308
diags = diags.Append(valDiags)
301309
inputVariables[subj.Name] = val
302-
if isSelf {
303-
self = val
304-
}
305310

306311
case addrs.LocalValue:
307312
val, valDiags := normalizeRefValue(s.Data.GetLocalValue(subj, rng))
308313
diags = diags.Append(valDiags)
309314
localValues[subj.Name] = val
310-
if isSelf {
311-
self = val
312-
}
313315

314316
case addrs.PathAttr:
315317
val, valDiags := normalizeRefValue(s.Data.GetPathAttr(subj, rng))
316318
diags = diags.Append(valDiags)
317319
pathAttrs[subj.Name] = val
318-
if isSelf {
319-
self = val
320-
}
321320

322321
case addrs.TerraformAttr:
323322
val, valDiags := normalizeRefValue(s.Data.GetTerraformAttr(subj, rng))
324323
diags = diags.Append(valDiags)
325324
terraformAttrs[subj.Name] = val
326-
if isSelf {
327-
self = val
328-
}
329325

330326
case addrs.CountAttr:
331327
val, valDiags := normalizeRefValue(s.Data.GetCountAttr(subj, rng))
332328
diags = diags.Append(valDiags)
333329
countAttrs[subj.Name] = val
334-
if isSelf {
335-
self = val
336-
}
337330

338331
case addrs.ForEachAttr:
339332
val, valDiags := normalizeRefValue(s.Data.GetForEachAttr(subj, rng))
340333
diags = diags.Append(valDiags)
341334
forEachAttrs[subj.Name] = val
342-
if isSelf {
343-
self = val
344-
}
345335

346336
default:
347337
// Should never happen
@@ -367,13 +357,9 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
367357
return ctx, diags
368358
}
369359

370-
func buildResourceObjects(resources map[string]map[string]map[addrs.InstanceKey]cty.Value) map[string]cty.Value {
360+
func buildResourceObjects(resources map[string]map[string]cty.Value) map[string]cty.Value {
371361
vals := make(map[string]cty.Value)
372-
for typeName, names := range resources {
373-
nameVals := make(map[string]cty.Value)
374-
for name, keys := range names {
375-
nameVals[name] = buildInstanceObjects(keys)
376-
}
362+
for typeName, nameVals := range resources {
377363
vals[typeName] = cty.ObjectVal(nameVals)
378364
}
379365
return vals

0 commit comments

Comments
 (0)