change lang eval to also only lookup resources
Continue only evaluating resource at a whole and push the indexing of the resource down into the expression evaluation. The exception here is that `self` must be an instance which must be extracted from the resource. We now also add the entire resource to the context, which was previously only partially populated with the self referenced instance.
This commit is contained in:
parent
da8ec6b483
commit
c49f976308
|
@ -9,7 +9,7 @@ import (
|
|||
type dataForTests struct {
|
||||
CountAttrs map[string]cty.Value
|
||||
ForEachAttrs map[string]cty.Value
|
||||
ResourceInstances map[string]cty.Value
|
||||
Resources map[string]cty.Value
|
||||
LocalValues map[string]cty.Value
|
||||
Modules map[string]cty.Value
|
||||
PathAttrs map[string]cty.Value
|
||||
|
@ -31,8 +31,8 @@ func (d *dataForTests) GetForEachAttr(addr addrs.ForEachAttr, rng tfdiags.Source
|
|||
return d.ForEachAttrs[addr.Name], nil
|
||||
}
|
||||
|
||||
func (d *dataForTests) GetResourceInstance(addr addrs.ResourceInstance, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
||||
return d.ResourceInstances[addr.String()], nil
|
||||
func (d *dataForTests) GetResource(addr addrs.Resource, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
||||
return d.Resources[addr.String()], nil
|
||||
}
|
||||
|
||||
func (d *dataForTests) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
||||
|
|
80
lang/eval.go
80
lang/eval.go
|
@ -208,7 +208,6 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
|
|||
|
||||
for _, ref := range refs {
|
||||
rng := ref.SourceRange
|
||||
isSelf := false
|
||||
|
||||
rawSubj := ref.Subject
|
||||
if rawSubj == addrs.Self {
|
||||
|
@ -226,19 +225,62 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
|
|||
continue
|
||||
}
|
||||
|
||||
// Treat "self" as an alias for the configured self address.
|
||||
rawSubj = selfAddr
|
||||
isSelf = true
|
||||
// self can only be used within a resource instance
|
||||
subj := selfAddr.(addrs.ResourceInstance)
|
||||
|
||||
if rawSubj == addrs.Self {
|
||||
if selfAddr == addrs.Self {
|
||||
// Programming error: the self address cannot alias itself.
|
||||
panic("scope SelfAddr attempting to alias itself")
|
||||
}
|
||||
|
||||
val, valDiags := normalizeRefValue(s.Data.GetResource(subj.ContainingResource(), rng))
|
||||
|
||||
diags = diags.Append(valDiags)
|
||||
|
||||
// Self is an exception in that it must always resolve to a
|
||||
// particular instance. We will still insert the full resource into
|
||||
// the context below.
|
||||
switch k := subj.Key.(type) {
|
||||
case addrs.IntKey:
|
||||
self = val.Index(cty.NumberIntVal(int64(k)))
|
||||
case addrs.StringKey:
|
||||
self = val.Index(cty.StringVal(string(k)))
|
||||
default:
|
||||
self = val
|
||||
}
|
||||
|
||||
r := subj.Resource
|
||||
if managedResources[r.Type] == nil {
|
||||
managedResources[r.Type] = make(map[string]cty.Value)
|
||||
}
|
||||
managedResources[r.Type][r.Name] = val
|
||||
continue
|
||||
}
|
||||
|
||||
// This type switch must cover all of the "Referenceable" implementations
|
||||
// in package addrs.
|
||||
switch subj := rawSubj.(type) {
|
||||
case addrs.Resource:
|
||||
panic("RESOURCE REFERENCES DON'T HIT THIS")
|
||||
|
||||
var into map[string]map[string]cty.Value
|
||||
switch subj.Mode {
|
||||
case addrs.ManagedResourceMode:
|
||||
into = managedResources
|
||||
case addrs.DataResourceMode:
|
||||
into = dataResources
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported ResourceMode %s", subj.Mode))
|
||||
}
|
||||
|
||||
val, valDiags := normalizeRefValue(s.Data.GetResource(subj, rng))
|
||||
diags = diags.Append(valDiags)
|
||||
|
||||
r := subj
|
||||
if into[r.Type] == nil {
|
||||
into[r.Type] = make(map[string]cty.Value)
|
||||
}
|
||||
into[r.Type][r.Name] = val
|
||||
|
||||
case addrs.ResourceInstance:
|
||||
var into map[string]map[string]cty.Value
|
||||
|
@ -252,6 +294,7 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
|
|||
}
|
||||
|
||||
val, valDiags := normalizeRefValue(s.Data.GetResource(subj.ContainingResource(), rng))
|
||||
|
||||
diags = diags.Append(valDiags)
|
||||
|
||||
r := subj.Resource
|
||||
|
@ -259,9 +302,6 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
|
|||
into[r.Type] = make(map[string]cty.Value)
|
||||
}
|
||||
into[r.Type][r.Name] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
case addrs.ModuleCallInstance:
|
||||
val, valDiags := normalizeRefValue(s.Data.GetModuleInstance(subj, rng))
|
||||
|
@ -271,9 +311,6 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
|
|||
wholeModules[subj.Call.Name] = make(map[addrs.InstanceKey]cty.Value)
|
||||
}
|
||||
wholeModules[subj.Call.Name][subj.Key] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
case addrs.ModuleCallOutput:
|
||||
val, valDiags := normalizeRefValue(s.Data.GetModuleInstanceOutput(subj, rng))
|
||||
|
@ -288,57 +325,36 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
|
|||
moduleOutputs[callName][callKey] = make(map[string]cty.Value)
|
||||
}
|
||||
moduleOutputs[callName][callKey][subj.Name] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
case addrs.InputVariable:
|
||||
val, valDiags := normalizeRefValue(s.Data.GetInputVariable(subj, rng))
|
||||
diags = diags.Append(valDiags)
|
||||
inputVariables[subj.Name] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
case addrs.LocalValue:
|
||||
val, valDiags := normalizeRefValue(s.Data.GetLocalValue(subj, rng))
|
||||
diags = diags.Append(valDiags)
|
||||
localValues[subj.Name] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
case addrs.PathAttr:
|
||||
val, valDiags := normalizeRefValue(s.Data.GetPathAttr(subj, rng))
|
||||
diags = diags.Append(valDiags)
|
||||
pathAttrs[subj.Name] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
case addrs.TerraformAttr:
|
||||
val, valDiags := normalizeRefValue(s.Data.GetTerraformAttr(subj, rng))
|
||||
diags = diags.Append(valDiags)
|
||||
terraformAttrs[subj.Name] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
case addrs.CountAttr:
|
||||
val, valDiags := normalizeRefValue(s.Data.GetCountAttr(subj, rng))
|
||||
diags = diags.Append(valDiags)
|
||||
countAttrs[subj.Name] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
case addrs.ForEachAttr:
|
||||
val, valDiags := normalizeRefValue(s.Data.GetForEachAttr(subj, rng))
|
||||
diags = diags.Append(valDiags)
|
||||
forEachAttrs[subj.Name] = val
|
||||
if isSelf {
|
||||
self = val
|
||||
}
|
||||
|
||||
default:
|
||||
// Should never happen
|
||||
|
|
|
@ -24,7 +24,7 @@ func TestScopeEvalContext(t *testing.T) {
|
|||
"key": cty.StringVal("a"),
|
||||
"value": cty.NumberIntVal(1),
|
||||
},
|
||||
ResourceInstances: map[string]cty.Value{
|
||||
Resources: map[string]cty.Value{
|
||||
"null_resource.foo": cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("bar"),
|
||||
}),
|
||||
|
@ -39,6 +39,14 @@ func TestScopeEvalContext(t *testing.T) {
|
|||
"attr": cty.StringVal("multi1"),
|
||||
}),
|
||||
}),
|
||||
"null_resource.each": cty.ObjectVal(map[string]cty.Value{
|
||||
"each0": cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("each0"),
|
||||
}),
|
||||
"each1": cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("each1"),
|
||||
}),
|
||||
}),
|
||||
"null_resource.multi[1]": cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("multi1"),
|
||||
}),
|
||||
|
@ -139,11 +147,14 @@ func TestScopeEvalContext(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
// at this level, all instance references return the entire resource
|
||||
`null_resource.multi[1]`,
|
||||
map[string]cty.Value{
|
||||
"null_resource": cty.ObjectVal(map[string]cty.Value{
|
||||
"multi": cty.TupleVal([]cty.Value{
|
||||
cty.DynamicVal,
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("multi0"),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("multi1"),
|
||||
}),
|
||||
|
@ -151,6 +162,22 @@ func TestScopeEvalContext(t *testing.T) {
|
|||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
// at this level, all instance references return the entire resource
|
||||
`null_resource.each["each1"]`,
|
||||
map[string]cty.Value{
|
||||
"null_resource": cty.ObjectVal(map[string]cty.Value{
|
||||
"each": cty.ObjectVal(map[string]cty.Value{
|
||||
"each0": cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("each0"),
|
||||
}),
|
||||
"each1": cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("each1"),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
`foo(null_resource.multi, null_resource.multi[1])`,
|
||||
map[string]cty.Value{
|
||||
|
@ -215,7 +242,9 @@ func TestScopeEvalContext(t *testing.T) {
|
|||
// expanded here and then copied into "self".
|
||||
"null_resource": cty.ObjectVal(map[string]cty.Value{
|
||||
"multi": cty.TupleVal([]cty.Value{
|
||||
cty.DynamicVal,
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("multi0"),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"attr": cty.StringVal("multi1"),
|
||||
}),
|
||||
|
|
Loading…
Reference in New Issue