change plan to store individual relevant attrs

Storing individual contributing attributes will allow finer tuning of
the plan rendering.

add contributing to outputs
This commit is contained in:
James Bardin 2022-02-04 13:34:43 -05:00
parent 620caa983c
commit c02e8bc5b3
3 changed files with 28 additions and 41 deletions

View File

@ -334,8 +334,8 @@ func renderChangesDetectedByRefresh(plan *plans.Plan, schemas *terraform.Schemas
// If this is not a refresh-only plan, we will need to filter out any // If this is not a refresh-only plan, we will need to filter out any
// non-relevant changes to reduce plan output. // non-relevant changes to reduce plan output.
relevant := make(map[string]bool) relevant := make(map[string]bool)
for _, r := range plan.RelevantResources { for _, r := range plan.RelevantAttributes {
relevant[r.String()] = true relevant[r.Resource.String()] = true
} }
// In refresh-only mode, we show all resources marked as drifted, // In refresh-only mode, we show all resources marked as drifted,

View File

@ -5,6 +5,7 @@ import (
"github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs/configschema" "github.com/hashicorp/terraform/internal/configs/configschema"
"github.com/hashicorp/terraform/internal/lang/globalref"
"github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/states"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
) )
@ -36,20 +37,15 @@ type Plan struct {
ForceReplaceAddrs []addrs.AbsResourceInstance ForceReplaceAddrs []addrs.AbsResourceInstance
Backend Backend Backend Backend
// RelevantResources is a set of resource addresses that are either // RelevantAttributes is a set of resource addresses and attributes that are
// directly affected by proposed changes or may have indirectly contributed // either directly affected by proposed changes or may have indirectly
// to them via references in expressions. // contributed to them via references in expressions.
// //
// This is the result of a heuristic and is intended only as a hint to // This is the result of a heuristic and is intended only as a hint to
// the UI layer in case it wants to emphasize or de-emphasize certain // the UI layer in case it wants to emphasize or de-emphasize certain
// resources. Don't use this to drive any non-cosmetic behavior, especially // resources. Don't use this to drive any non-cosmetic behavior, especially
// including anything that would be subject to compatibility constraints. // including anything that would be subject to compatibility constraints.
// RelevantAttributes []globalref.ResourceAttr
// FIXME: This result currently doesn't survive round-tripping through a
// saved plan file, and so it'll be populated only for a freshly-created
// plan that has only existed in memory so far. When reloading a saved
// plan it will always appear as if there are no "relevant resources".
RelevantResources []addrs.AbsResource
// PrevRunState and PriorState both describe the situation that the plan // PrevRunState and PriorState both describe the situation that the plan
// was derived from: // was derived from:

View File

@ -200,10 +200,10 @@ The -target option is not for routine use, and is provided only for exceptional
panic("nil plan but no errors") panic("nil plan but no errors")
} }
relevantResources, rDiags := c.relevantResourcesForPlan(config, plan) relevantAttrs, rDiags := c.relevantResourceAttrsForPlan(config, plan)
diags = diags.Append(rDiags) diags = diags.Append(rDiags)
plan.RelevantResources = relevantResources plan.RelevantAttributes = relevantAttrs
return plan, diags return plan, diags
} }
@ -366,10 +366,10 @@ func (c *Context) destroyPlan(config *configs.Config, prevRunState *states.State
destroyPlan.PrevRunState = pendingPlan.PrevRunState destroyPlan.PrevRunState = pendingPlan.PrevRunState
} }
relevantResources, rDiags := c.relevantResourcesForPlan(config, destroyPlan) relevantAttrs, rDiags := c.relevantResourceAttrsForPlan(config, destroyPlan)
diags = diags.Append(rDiags) diags = diags.Append(rDiags)
destroyPlan.RelevantResources = relevantResources destroyPlan.RelevantAttributes = relevantAttrs
return destroyPlan, diags return destroyPlan, diags
} }
@ -763,47 +763,38 @@ func (c *Context) referenceAnalyzer(config *configs.Config, state *states.State)
// relevantResourcesForPlan implements the heuristic we use to populate the // relevantResourcesForPlan implements the heuristic we use to populate the
// RelevantResources field of returned plans. // RelevantResources field of returned plans.
func (c *Context) relevantResourcesForPlan(config *configs.Config, plan *plans.Plan) ([]addrs.AbsResource, tfdiags.Diagnostics) { func (c *Context) relevantResourceAttrsForPlan(config *configs.Config, plan *plans.Plan) ([]globalref.ResourceAttr, tfdiags.Diagnostics) {
azr, diags := c.referenceAnalyzer(config, plan.PriorState) azr, diags := c.referenceAnalyzer(config, plan.PriorState)
if diags.HasErrors() { if diags.HasErrors() {
return nil, diags return nil, diags
} }
// Our current strategy is that a resource is relevant if it either has
// a proposed change action directly, or if its attributes are used as
// any part of a resource that has a proposed change action. We don't
// consider individual changed attributes for now, because we can't
// really reason about any rules that providers might have about changes
// to one attribute implying a change to another.
// We'll use the string representation of a resource address as a unique
// key so we can dedupe our results.
relevant := make(map[string]addrs.AbsResource)
var refs []globalref.Reference var refs []globalref.Reference
for _, change := range plan.Changes.Resources { for _, change := range plan.Changes.Resources {
if change.Action == plans.NoOp { if change.Action == plans.NoOp {
continue continue
} }
instAddr := change.Addr
addr := instAddr.ContainingResource()
relevant[addr.String()] = addr
moreRefs := azr.ReferencesFromResourceInstance(instAddr) moreRefs := azr.ReferencesFromResourceInstance(change.Addr)
refs = append(refs, moreRefs...) refs = append(refs, moreRefs...)
} }
contributors := azr.ContributingResources(refs...) for _, change := range plan.Changes.Outputs {
for _, addr := range contributors { if change.Action == plans.NoOp {
relevant[addr.String()] = addr continue
} }
if len(relevant) == 0 { moreRefs := azr.ReferencesFromOutputValue(change.Addr)
return nil, diags refs = append(refs, moreRefs...)
} }
ret := make([]addrs.AbsResource, 0, len(relevant))
for _, addr := range relevant { var contributors []globalref.ResourceAttr
ret = append(ret, addr)
for _, ref := range azr.ContributingResourceReferences(refs...) {
if res, ok := ref.ResourceAttr(); ok {
contributors = append(contributors, res)
} }
return ret, diags }
return contributors, diags
} }