Skip to content

Commit

Permalink
remove GetModuleInstanceOutput
Browse files Browse the repository at this point in the history
There is no codepath that can use this any longer, since we need to
evaluate the modules as whole objects.

This means we're going to have to live for now with invalid module
output references returning "object" errors rather that "module".
  • Loading branch information
jbardin committed Apr 14, 2020
1 parent ad069b7 commit 42cee86
Show file tree
Hide file tree
Showing 3 changed files with 2 additions and 88 deletions.
1 change: 0 additions & 1 deletion lang/data.go
Expand Up @@ -27,7 +27,6 @@ type Data interface {
GetResource(addrs.Resource, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
GetLocalValue(addrs.LocalValue, tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics)
GetModule(addrs.ModuleCall, 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)
Expand Down
15 changes: 0 additions & 15 deletions lang/eval.go
Expand Up @@ -195,7 +195,6 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
dataResources := map[string]map[string]cty.Value{}
managedResources := map[string]map[string]cty.Value{}
wholeModules := map[string]cty.Value{}
moduleOutputs := map[string]map[addrs.InstanceKey]map[string]cty.Value{}
inputVariables := map[string]cty.Value{}
localValues := map[string]cty.Value{}
pathAttrs := map[string]cty.Value{}
Expand Down Expand Up @@ -292,20 +291,6 @@ func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceabl
diags = diags.Append(valDiags)
wholeModules[subj.Name] = val

case addrs.AbsModuleCallOutput:
val, valDiags := normalizeRefValue(s.Data.GetModuleInstanceOutput(subj, rng))
diags = diags.Append(valDiags)

callName := subj.Call.Call.Name
callKey := subj.Call.Key
if moduleOutputs[callName] == nil {
moduleOutputs[callName] = make(map[addrs.InstanceKey]map[string]cty.Value)
}
if moduleOutputs[callName][callKey] == nil {
moduleOutputs[callName][callKey] = make(map[string]cty.Value)
}
moduleOutputs[callName][callKey][subj.Name] = val

case addrs.InputVariable:
val, valDiags := normalizeRefValue(s.Data.GetInputVariable(subj, rng))
diags = diags.Append(valDiags)
Expand Down
74 changes: 2 additions & 72 deletions terraform/evaluate.go
Expand Up @@ -471,8 +471,8 @@ func (d *evaluationStateData) GetModule(addr addrs.ModuleCall, rng tfdiags.Sourc
}

// we shouldn't have any holes, but insert real values just in case,
// while trimming off any extra values that may have there from old
// entries.
// while trimming off any extra values that we may have from guessing
// the length via the state instances.
last := 0
for i, v := range vals {
if v.IsNull() {
Expand Down Expand Up @@ -510,76 +510,6 @@ func (d *evaluationStateData) GetModule(addr addrs.ModuleCall, rng tfdiags.Sourc
}
}

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
// the child module instances of our current module path.
absAddr := addr.AbsOutputValue(d.ModulePath)
moduleAddr := absAddr.Module

// First we'll consult the configuration to see if an output of this
// name is declared at all.
moduleConfig := d.Evaluator.Config.DescendentForInstance(moduleAddr)
if moduleConfig == nil {
// this doesn't happen in normal circumstances due to our validation
// pass, but it can turn up in some unusual situations, like in the
// "terraform console" repl where arbitrary expressions can be
// evaluated.
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: `Reference to undeclared module`,
Detail: fmt.Sprintf(`The configuration contains no %s.`, moduleAddr),
Subject: rng.ToHCL().Ptr(),
})
return cty.DynamicVal, diags
}

config := moduleConfig.Module.Outputs[addr.Name]
if config == nil {
var suggestions []string
for k := range moduleConfig.Module.Outputs {
suggestions = append(suggestions, k)
}
suggestion := nameSuggestion(addr.Name, suggestions)
if suggestion != "" {
suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
}

diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: `Reference to undeclared output value`,
Detail: fmt.Sprintf(`An output value with the name %q has not been declared in %s.%s`, addr.Name, moduleDisplayAddr(moduleAddr), suggestion),
Subject: rng.ToHCL().Ptr(),
})
return cty.DynamicVal, diags
}

// If a pending change is present in our current changeset then its value
// takes priority over what's in state. (It will usually be the same but
// will differ if the new value is unknown during planning.)
if changeSrc := d.Evaluator.Changes.GetOutputChange(absAddr); changeSrc != nil {
change, err := changeSrc.Decode()
if err != nil {
// This should happen only if someone has tampered with a plan
// file, so we won't bother with a pretty error for it.
diags = diags.Append(fmt.Errorf("planned change for %s could not be decoded: %s", absAddr, err))
return cty.DynamicVal, diags
}
// We care only about the "after" value, which is the value this output
// will take on after the plan is applied.
return change.After, diags
}

os := d.Evaluator.State.OutputValue(absAddr)
if os == nil {
// Not evaluated yet?
return cty.DynamicVal, diags
}

return os.Value, diags
}

func (d *evaluationStateData) GetPathAttr(addr addrs.PathAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
switch addr.Name {
Expand Down

0 comments on commit 42cee86

Please sign in to comment.