mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-03 20:50:59 -05:00
* actions: add invoke graph nodes * fix small bugs * add additional tests * remove whitespace * actions: invoke rendered actions * also fix up apply message * make description headers consistent * fix copyright headers * go generate
190 lines
5.4 KiB
Go
190 lines
5.4 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package jsonformat
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
|
|
"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
|
|
"github.com/hashicorp/terraform/internal/command/jsonformat/differ"
|
|
"github.com/hashicorp/terraform/internal/command/jsonformat/structured"
|
|
"github.com/hashicorp/terraform/internal/command/jsonformat/structured/attribute_path"
|
|
"github.com/hashicorp/terraform/internal/command/jsonplan"
|
|
"github.com/hashicorp/terraform/internal/command/jsonprovider"
|
|
"github.com/hashicorp/terraform/internal/configs"
|
|
"github.com/hashicorp/terraform/internal/plans"
|
|
)
|
|
|
|
func precomputeDiffs(plan Plan, mode plans.Mode) diffs {
|
|
diffs := diffs{
|
|
outputs: make(map[string]computed.Diff),
|
|
}
|
|
|
|
for _, drift := range plan.ResourceDrift {
|
|
|
|
var relevantAttrs attribute_path.Matcher
|
|
if mode == plans.RefreshOnlyMode {
|
|
// For a refresh only plan, we show all the drift.
|
|
relevantAttrs = attribute_path.AlwaysMatcher()
|
|
} else {
|
|
matcher := attribute_path.Empty(true)
|
|
|
|
// Otherwise we only want to show the drift changes that are
|
|
// relevant.
|
|
for _, attr := range plan.RelevantAttributes {
|
|
if len(attr.Resource) == 0 || attr.Resource == drift.Address {
|
|
matcher = attribute_path.AppendSingle(matcher, attr.Attr)
|
|
}
|
|
}
|
|
|
|
if len(matcher.Paths) > 0 {
|
|
relevantAttrs = matcher
|
|
}
|
|
}
|
|
|
|
if relevantAttrs == nil {
|
|
// If we couldn't build a relevant attribute matcher, then we are
|
|
// not going to show anything for this drift.
|
|
continue
|
|
}
|
|
|
|
schema := plan.getSchema(drift)
|
|
change := structured.FromJsonChange(drift.Change, relevantAttrs)
|
|
diffs.drift = append(diffs.drift, diff{
|
|
change: drift,
|
|
diff: differ.ComputeDiffForBlock(change, schema.Block),
|
|
})
|
|
}
|
|
|
|
for _, change := range plan.ResourceChanges {
|
|
schema := plan.getSchema(change)
|
|
structuredChange := structured.FromJsonChange(change.Change, attribute_path.AlwaysMatcher())
|
|
|
|
before := []jsonplan.ActionInvocation{}
|
|
after := []jsonplan.ActionInvocation{}
|
|
|
|
for _, action := range plan.ActionInvocations {
|
|
if action.LifecycleActionTrigger == nil || action.LifecycleActionTrigger.TriggeringResourceAddress != change.Address {
|
|
continue
|
|
}
|
|
|
|
switch action.LifecycleActionTrigger.ActionTriggerEvent {
|
|
case configs.BeforeCreate.String(), configs.BeforeUpdate.String(), configs.BeforeDestroy.String():
|
|
before = append(before, action)
|
|
case configs.AfterCreate.String(), configs.AfterUpdate.String(), configs.AfterDestroy.String():
|
|
after = append(after, action)
|
|
default:
|
|
// The switch should be exhaustive.
|
|
panic(fmt.Sprintf("Unexpected triggering event when rendering action %s", action.LifecycleActionTrigger.ActionTriggerEvent))
|
|
}
|
|
}
|
|
|
|
slices.SortFunc(before, jsonplan.ActionInvocationCompare)
|
|
slices.SortFunc(after, jsonplan.ActionInvocationCompare)
|
|
|
|
var beforeActionsTriggered []actionInvocation
|
|
var afterActionsTriggered []actionInvocation
|
|
for _, action := range before {
|
|
schema := plan.getActionSchema(action)
|
|
beforeActionsTriggered = append(beforeActionsTriggered, actionInvocation{
|
|
invocation: action,
|
|
schema: schema,
|
|
})
|
|
}
|
|
for _, action := range after {
|
|
schema := plan.getActionSchema(action)
|
|
afterActionsTriggered = append(afterActionsTriggered, actionInvocation{
|
|
invocation: action,
|
|
schema: schema,
|
|
})
|
|
}
|
|
|
|
diffs.changes = append(diffs.changes, diff{
|
|
change: change,
|
|
diff: differ.ComputeDiffForBlock(structuredChange, schema.Block),
|
|
beforeActionsTriggered: beforeActionsTriggered,
|
|
afterActionsTriggered: afterActionsTriggered,
|
|
})
|
|
}
|
|
|
|
for _, action := range plan.ActionInvocations {
|
|
if action.InvokeActionTrigger == nil {
|
|
// lifecycle actions are handled within the resource
|
|
continue
|
|
}
|
|
diffs.actions = append(diffs.actions, actionInvocation{
|
|
invocation: action,
|
|
schema: plan.getActionSchema(action),
|
|
})
|
|
}
|
|
|
|
for _, change := range plan.DeferredChanges {
|
|
schema := plan.getSchema(change.ResourceChange)
|
|
structuredChange := structured.FromJsonChange(change.ResourceChange.Change, attribute_path.AlwaysMatcher())
|
|
diffs.deferred = append(diffs.deferred, deferredDiff{
|
|
reason: change.Reason,
|
|
diff: diff{
|
|
change: change.ResourceChange,
|
|
diff: differ.ComputeDiffForBlock(structuredChange, schema.Block),
|
|
},
|
|
})
|
|
}
|
|
|
|
for key, output := range plan.OutputChanges {
|
|
change := structured.FromJsonChange(output, attribute_path.AlwaysMatcher())
|
|
diffs.outputs[key] = differ.ComputeDiffForOutput(change)
|
|
}
|
|
|
|
return diffs
|
|
}
|
|
|
|
type diffs struct {
|
|
drift []diff
|
|
changes []diff
|
|
deferred []deferredDiff
|
|
actions []actionInvocation
|
|
outputs map[string]computed.Diff
|
|
}
|
|
|
|
func (d diffs) Empty() bool {
|
|
for _, change := range d.changes {
|
|
if change.diff.Action != plans.NoOp || change.Moved() {
|
|
return false
|
|
}
|
|
}
|
|
|
|
for _, output := range d.outputs {
|
|
if output.Action != plans.NoOp {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
type diff struct {
|
|
change jsonplan.ResourceChange
|
|
diff computed.Diff
|
|
beforeActionsTriggered []actionInvocation
|
|
afterActionsTriggered []actionInvocation
|
|
}
|
|
|
|
type actionInvocation struct {
|
|
invocation jsonplan.ActionInvocation
|
|
schema *jsonprovider.ActionSchema
|
|
}
|
|
|
|
func (d diff) Moved() bool {
|
|
return len(d.change.PreviousAddress) > 0 && d.change.PreviousAddress != d.change.Address
|
|
}
|
|
|
|
func (d diff) Importing() bool {
|
|
return d.change.Change.Importing != nil
|
|
}
|
|
|
|
type deferredDiff struct {
|
|
diff diff
|
|
reason string
|
|
}
|