outputs should not be checked during destroy

Module output may need to be evaluated during destroy in order to
possibly be used by providers. The final state however is that all
objects are destroyed, so preconditions should not be evaluated.
This commit is contained in:
James Bardin 2022-10-14 18:08:18 -04:00
parent 71837d187b
commit 8a24d73d15
2 changed files with 45 additions and 31 deletions

View File

@ -20,11 +20,12 @@ import (
// nodeExpandOutput is the placeholder for a non-root module output that has // nodeExpandOutput is the placeholder for a non-root module output that has
// not yet had its module path expanded. // not yet had its module path expanded.
type nodeExpandOutput struct { type nodeExpandOutput struct {
Addr addrs.OutputValue Addr addrs.OutputValue
Module addrs.Module Module addrs.Module
Config *configs.Output Config *configs.Output
Destroy bool DestroyPlan bool
RefreshOnly bool DestroyApply bool
RefreshOnly bool
// Planning is set to true when this node is in a graph that was produced // Planning is set to true when this node is in a graph that was produced
// by the plan graph builder, as opposed to the apply graph builder. // by the plan graph builder, as opposed to the apply graph builder.
@ -52,7 +53,7 @@ func (n *nodeExpandOutput) temporaryValue() bool {
} }
func (n *nodeExpandOutput) DynamicExpand(ctx EvalContext) (*Graph, error) { func (n *nodeExpandOutput) DynamicExpand(ctx EvalContext) (*Graph, error) {
if n.Destroy { if n.DestroyPlan {
// if we're planning a destroy, we only need to handle the root outputs. // if we're planning a destroy, we only need to handle the root outputs.
// The destroy plan doesn't evaluate any other config, so we can skip // The destroy plan doesn't evaluate any other config, so we can skip
// the rest of the outputs. // the rest of the outputs.
@ -105,10 +106,11 @@ func (n *nodeExpandOutput) DynamicExpand(ctx EvalContext) (*Graph, error) {
} }
o := &NodeApplyableOutput{ o := &NodeApplyableOutput{
Addr: absAddr, Addr: absAddr,
Config: n.Config, Config: n.Config,
Change: change, Change: change,
RefreshOnly: n.RefreshOnly, RefreshOnly: n.RefreshOnly,
DestroyApply: n.DestroyApply,
} }
log.Printf("[TRACE] Expanding output: adding %s as %T", o.Addr.String(), o) log.Printf("[TRACE] Expanding output: adding %s as %T", o.Addr.String(), o)
g.Add(o) g.Add(o)
@ -192,8 +194,11 @@ func (n *nodeExpandOutput) ReferenceOutside() (selfPath, referencePath addrs.Mod
// GraphNodeReferencer // GraphNodeReferencer
func (n *nodeExpandOutput) References() []*addrs.Reference { func (n *nodeExpandOutput) References() []*addrs.Reference {
// root outputs might be destroyable, and may not reference anything in // DestroyNodes do not reference anything.
// that case if n.Module.IsRoot() && n.DestroyApply {
return nil
}
return referencesForOutput(n.Config) return referencesForOutput(n.Config)
} }
@ -208,6 +213,10 @@ type NodeApplyableOutput struct {
// Refresh-only mode means that any failing output preconditions are // Refresh-only mode means that any failing output preconditions are
// reported as warnings rather than errors // reported as warnings rather than errors
RefreshOnly bool RefreshOnly bool
// DestroyApply indicates that we are applying a destroy plan, and do not
// need to account for conditional blocks.
DestroyApply bool
} }
var ( var (
@ -321,19 +330,23 @@ func (n *NodeApplyableOutput) Execute(ctx EvalContext, op walkOperation) (diags
} }
} }
checkRuleSeverity := tfdiags.Error // Checks are not evaluated during a destroy. The checks may fail, may not
if n.RefreshOnly { // be valid, or may not have been registered at all.
checkRuleSeverity = tfdiags.Warning if !n.DestroyApply {
} checkRuleSeverity := tfdiags.Error
checkDiags := evalCheckRules( if n.RefreshOnly {
addrs.OutputPrecondition, checkRuleSeverity = tfdiags.Warning
n.Config.Preconditions, }
ctx, n.Addr, EvalDataForNoInstanceKey, checkDiags := evalCheckRules(
checkRuleSeverity, addrs.OutputPrecondition,
) n.Config.Preconditions,
diags = diags.Append(checkDiags) ctx, n.Addr, EvalDataForNoInstanceKey,
if diags.HasErrors() { checkRuleSeverity,
return diags // failed preconditions prevent further evaluation )
diags = diags.Append(checkDiags)
if diags.HasErrors() {
return diags // failed preconditions prevent further evaluation
}
} }
// If there was no change recorded, or the recorded change was not wholly // If there was no change recorded, or the recorded change was not wholly

View File

@ -92,12 +92,13 @@ func (t *OutputTransformer) transform(g *Graph, c *configs.Config) error {
default: default:
node = &nodeExpandOutput{ node = &nodeExpandOutput{
Addr: addr, Addr: addr,
Module: c.Path, Module: c.Path,
Config: o, Config: o,
Destroy: t.removeRootOutputs, DestroyPlan: t.removeRootOutputs,
RefreshOnly: t.RefreshOnly, DestroyApply: t.destroyApply,
Planning: t.Planning, RefreshOnly: t.RefreshOnly,
Planning: t.Planning,
} }
} }