diff --git a/addrs/module_call.go b/addrs/module_call.go index 09596cc84..c496cdc46 100644 --- a/addrs/module_call.go +++ b/addrs/module_call.go @@ -51,31 +51,43 @@ func (c ModuleCallInstance) ModuleInstance(caller ModuleInstance) ModuleInstance return caller.Child(c.Call.Name, c.Key) } -// Output returns the address of an output of the receiver identified by its +// Output returns the absolute address of an output of the receiver identified by its // name. -func (c ModuleCallInstance) Output(name string) ModuleCallOutput { - return ModuleCallOutput{ +func (c ModuleCallInstance) Output(name string) AbsModuleCallOutput { + return AbsModuleCallOutput{ Call: c, Name: name, } } -// ModuleCallOutput is the address of a particular named output produced by -// an instance of a module call. +// ModuleCallOutput is the address of a named output and its associated +// ModuleCall, which may expand into multiple module instances type ModuleCallOutput struct { + referenceable + Call ModuleCall + Name string +} + +func (m ModuleCallOutput) String() string { + return fmt.Sprintf("%s.%s", m.Call.String(), m.Name) +} + +// AbsModuleCallOutput is the address of a particular named output produced by +// an instance of a module call. +type AbsModuleCallOutput struct { referenceable Call ModuleCallInstance Name string } -func (co ModuleCallOutput) String() string { +func (co AbsModuleCallOutput) String() string { return fmt.Sprintf("%s.%s", co.Call.String(), co.Name) } // AbsOutputValue returns the absolute output value address that corresponds // to the receving module call output address, once resolved in the given // calling module. -func (co ModuleCallOutput) AbsOutputValue(caller ModuleInstance) AbsOutputValue { +func (co AbsModuleCallOutput) AbsOutputValue(caller ModuleInstance) AbsOutputValue { moduleAddr := co.Call.ModuleInstance(caller) return moduleAddr.OutputValue(co.Name) } diff --git a/addrs/output_value.go b/addrs/output_value.go index bcd923acb..f97eca19e 100644 --- a/addrs/output_value.go +++ b/addrs/output_value.go @@ -62,13 +62,13 @@ func (v AbsOutputValue) String() string { // // The root module does not have a call, and so this method cannot be used // with outputs in the root module, and will panic in that case. -func (v AbsOutputValue) ModuleCallOutput() (ModuleInstance, ModuleCallOutput) { +func (v AbsOutputValue) ModuleCallOutput() (ModuleInstance, AbsModuleCallOutput) { if v.Module.IsRoot() { panic("ReferenceFromCall used with root module output") } caller, call := v.Module.CallInstance() - return caller, ModuleCallOutput{ + return caller, AbsModuleCallOutput{ Call: call, Name: v.OutputValue.Name, } diff --git a/addrs/parse_ref.go b/addrs/parse_ref.go index d5142690b..cd8b114f6 100644 --- a/addrs/parse_ref.go +++ b/addrs/parse_ref.go @@ -171,7 +171,7 @@ func parseRef(traversal hcl.Traversal) (*Reference, tfdiags.Diagnostics) { if attrTrav, ok := remain[0].(hcl.TraverseAttr); ok { remain = remain[1:] return &Reference{ - Subject: ModuleCallOutput{ + Subject: AbsModuleCallOutput{ Name: attrTrav.Name, Call: callInstance, }, diff --git a/addrs/parse_ref_test.go b/addrs/parse_ref_test.go index 9614aa8b5..be1eb244e 100644 --- a/addrs/parse_ref_test.go +++ b/addrs/parse_ref_test.go @@ -296,7 +296,7 @@ func TestParseRef(t *testing.T) { { `module.foo.bar`, &Reference{ - Subject: ModuleCallOutput{ + Subject: AbsModuleCallOutput{ Call: ModuleCallInstance{ Call: ModuleCall{ Name: "foo", @@ -314,7 +314,7 @@ func TestParseRef(t *testing.T) { { `module.foo.bar.baz`, &Reference{ - Subject: ModuleCallOutput{ + Subject: AbsModuleCallOutput{ Call: ModuleCallInstance{ Call: ModuleCall{ Name: "foo", @@ -357,7 +357,7 @@ func TestParseRef(t *testing.T) { { `module.foo["baz"].bar`, &Reference{ - Subject: ModuleCallOutput{ + Subject: AbsModuleCallOutput{ Call: ModuleCallInstance{ Call: ModuleCall{ Name: "foo", @@ -376,7 +376,7 @@ func TestParseRef(t *testing.T) { { `module.foo["baz"].bar.boop`, &Reference{ - Subject: ModuleCallOutput{ + Subject: AbsModuleCallOutput{ Call: ModuleCallInstance{ Call: ModuleCall{ Name: "foo", diff --git a/lang/data.go b/lang/data.go index ebc008e35..27ee17028 100644 --- a/lang/data.go +++ b/lang/data.go @@ -27,7 +27,7 @@ type Data interface { GetResource(addrs.Resource, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) GetLocalValue(addrs.LocalValue, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) GetModuleInstance(addrs.ModuleCallInstance, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) - GetModuleInstanceOutput(addrs.ModuleCallOutput, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) + GetModuleInstanceOutput(addrs.AbsModuleCallOutput, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) GetPathAttr(addrs.PathAttr, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) GetTerraformAttr(addrs.TerraformAttr, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) GetInputVariable(addrs.InputVariable, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) diff --git a/lang/data_test.go b/lang/data_test.go index fd87861fc..ba825bd4d 100644 --- a/lang/data_test.go +++ b/lang/data_test.go @@ -47,7 +47,7 @@ func (d *dataForTests) GetModuleInstance(addr addrs.ModuleCallInstance, rng tfdi return d.Modules[addr.String()], nil } -func (d *dataForTests) GetModuleInstanceOutput(addr addrs.ModuleCallOutput, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { +func (d *dataForTests) GetModuleInstanceOutput(addr addrs.AbsModuleCallOutput, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { // This will panic if the module object does not have the requested attribute obj := d.Modules[addr.Call.String()] return obj.GetAttr(addr.Name), nil diff --git a/lang/eval.go b/lang/eval.go index bfacd671a..0ddee410a 100644 --- a/lang/eval.go +++ b/lang/eval.go @@ -293,7 +293,7 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl } wholeModules[subj.Call.Name][subj.Key] = val - case addrs.ModuleCallOutput: + case addrs.AbsModuleCallOutput: val, valDiags := normalizeRefValue(s.Data.GetModuleInstanceOutput(subj, rng)) diags = diags.Append(valDiags) diff --git a/terraform/evaluate.go b/terraform/evaluate.go index 96a981070..bde3b2367 100644 --- a/terraform/evaluate.go +++ b/terraform/evaluate.go @@ -386,7 +386,7 @@ func (d *evaluationStateData) GetModuleInstance(addr addrs.ModuleCallInstance, r return cty.ObjectVal(vals), diags } -func (d *evaluationStateData) GetModuleInstanceOutput(addr addrs.ModuleCallOutput, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { +func (d *evaluationStateData) GetModuleInstanceOutput(addr addrs.AbsModuleCallOutput, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics // Output results live in the module that declares them, which is one of diff --git a/terraform/evaluate_valid.go b/terraform/evaluate_valid.go index 18b8c4118..5fabb96be 100644 --- a/terraform/evaluate_valid.go +++ b/terraform/evaluate_valid.go @@ -91,7 +91,7 @@ func (d *evaluationStateData) staticValidateReference(ref *addrs.Reference, self return d.staticValidateModuleCallReference(modCfg, addr, ref.Remaining, ref.SourceRange) case addrs.ModuleCallInstance: return d.staticValidateModuleCallReference(modCfg, addr.Call, ref.Remaining, ref.SourceRange) - case addrs.ModuleCallOutput: + case addrs.AbsModuleCallOutput: // This one is a funny one because we will take the output name referenced // and use it to fake up a "remaining" that would make sense for the // module call itself, rather than for the specific output, and then diff --git a/terraform/node_output.go b/terraform/node_output.go index ce9fc0d22..3d3c80a91 100644 --- a/terraform/node_output.go +++ b/terraform/node_output.go @@ -64,7 +64,7 @@ func (n *NodePlannableOutput) ReferenceableAddrs() []addrs.Referenceable { // module itself. _, call := n.Module.Call() callOutput := addrs.ModuleCallOutput{ - Call: call.Instance(addrs.NoKey), + Call: call, Name: n.Addr.Name, }