/
githubmirror
/
terraform
Обзор
Документация
Войти
/
githubmirror
/
terraform
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
internal/command/views/json/change.go
211 строк
7 KB
James Bardin
expose on_failure to the json hook output
10 июл 2026, 18:43
10 июл 2026, 18:43
ccd981e
Код
Авторство
О чём код?
// Copyright IBM Corp. 2014, 2026 // SPDX-License-Identifier: BUSL-1.1 package json import ( "fmt" "github.com/hashicorp/terraform/internal/plans" ) func NewResourceInstanceChange(change *plans.ResourceInstanceChangeSrc) *ResourceInstanceChange { c := &ResourceInstanceChange{ Resource: newResourceAddr(change.Addr), Action: changeAction(change.Action), Reason: changeReason(change.ActionReason), GeneratedConfig: change.GeneratedConfig, } // The order here matters, we want the moved action to take precedence over // the import action. We're basically taking "the most recent action" as the // primary action in the streamed logs. That is to say, that if a resource // is imported and then moved in a single operation then the change for that // resource will be reported as ActionMove while the Importing flag will // still be set to true. // // Since both the moved and imported actions only overwrite a NoOp this // behaviour is consistent across the other actions as well. Something that // is imported and then updated, or moved and then updated, will have the // ActionUpdate as the recognised action for the change. if !change.Addr.Equal(change.PrevRunAddr) { if c.Action == ActionNoOp { c.Action = ActionMove } pr := newResourceAddr(change.PrevRunAddr) c.PreviousResource = &pr } if change.Importing != nil { if c.Action == ActionNoOp { c.Action = ActionImport } c.Importing = &Importing{ID: change.Importing.ID} } return c } type ResourceInstanceChange struct { Resource ResourceAddr `json:"resource"` PreviousResource *ResourceAddr `json:"previous_resource,omitempty"` Action ChangeAction `json:"action"` Reason ChangeReason `json:"reason,omitempty"` Importing *Importing `json:"importing,omitempty"` GeneratedConfig string `json:"generated_config,omitempty"` } func (c *ResourceInstanceChange) String() string { return fmt.Sprintf("%s: Plan to %s", c.Resource.Addr, c.Action) } func NewPlannedActionInvocation(aiSrc *plans.ActionInvocationInstanceSrc) *ActionInvocation { ai := &ActionInvocation{ Action: newActionAddr(aiSrc.Addr), } switch trigger := aiSrc.ActionTrigger.(type) { case *plans.ResourceActionTrigger: ai.LifecycleTrigger = &ActionInvocationLifecycleTrigger{ TriggeringResource: newResourceAddr(trigger.TriggeringResourceAddr), TriggeringEvent: trigger.ActionTriggerEvent.String(), ActionTriggerBlockIndex: trigger.ActionTriggerBlockIndex, ActionsListIndex: trigger.ActionsListIndex, OnFailure: trigger.ActionOnFailure.String(), } case *plans.InvokeActionTrigger: ai.InvokeTrigger = new(ActionInvocationInvokeTrigger) } return ai } type ActionInvocation struct { Action ActionAddr `json:"action_addr"` LifecycleTrigger *ActionInvocationLifecycleTrigger `json:"lifecycle_trigger,omitempty"` InvokeTrigger *ActionInvocationInvokeTrigger `json:"action_trigger,omitempty"` } func (c *ActionInvocation) String() string { if c.LifecycleTrigger != nil { return fmt.Sprintf("%s: triggered by %s trigger on %s", c.Action.Addr, c.LifecycleTrigger.TriggeringEvent, c.LifecycleTrigger.TriggeringResource) } return c.Action.Addr } type ActionInvocationLifecycleTrigger struct { TriggeringResource ResourceAddr `json:"triggering_resource"` TriggeringEvent string `json:"triggering_event"` ActionTriggerBlockIndex int `json:"action_trigger_block_index"` ActionsListIndex int `json:"actions_list_index"` OnFailure string `json:"on_failure"` } type ActionInvocationInvokeTrigger struct{} type ChangeAction string const ( ActionNoOp ChangeAction = "noop" ActionMove ChangeAction = "move" ActionForget ChangeAction = "remove" ActionCreate ChangeAction = "create" ActionRead ChangeAction = "read" ActionUpdate ChangeAction = "update" ActionReplace ChangeAction = "replace" ActionDelete ChangeAction = "delete" ActionImport ChangeAction = "import" // While ephemeral resources do not represent a change // or participate in the plan in the same way as the above // we declare them here for convenience in helper functions. ActionOpen ChangeAction = "open" ActionRenew ChangeAction = "renew" ActionClose ChangeAction = "close" ) func changeAction(action plans.Action) ChangeAction { switch action { case plans.NoOp: return ActionNoOp case plans.Create: return ActionCreate case plans.Read: return ActionRead case plans.Update: return ActionUpdate case plans.DeleteThenCreate, plans.CreateThenDelete, plans.CreateThenForget: return ActionReplace case plans.Delete: return ActionDelete case plans.Forget: return ActionForget case plans.Open: return ActionOpen case plans.Renew: return ActionRenew case plans.Close: return ActionClose default: return ActionNoOp } } type ChangeReason string const ( ReasonNone ChangeReason = "" ReasonTainted ChangeReason = "tainted" ReasonRequested ChangeReason = "requested" ReasonReplaceTriggeredBy ChangeReason = "replace_triggered_by" ReasonCannotUpdate ChangeReason = "cannot_update" ReasonUnknown ChangeReason = "unknown" ReasonDeleteBecauseNoResourceConfig ChangeReason = "delete_because_no_resource_config" ReasonDeleteBecauseWrongRepetition ChangeReason = "delete_because_wrong_repetition" ReasonDeleteBecauseCountIndex ChangeReason = "delete_because_count_index" ReasonDeleteBecauseEachKey ChangeReason = "delete_because_each_key" ReasonDeleteBecauseNoModule ChangeReason = "delete_because_no_module" ReasonDeleteBecauseNoMoveTarget ChangeReason = "delete_because_no_move_target" ReasonReadBecauseConfigUnknown ChangeReason = "read_because_config_unknown" ReasonReadBecauseDependencyPending ChangeReason = "read_because_dependency_pending" ReasonReadBecauseCheckNested ChangeReason = "read_because_check_nested" ) func changeReason(reason plans.ResourceInstanceChangeActionReason) ChangeReason { switch reason { case plans.ResourceInstanceChangeNoReason: return ReasonNone case plans.ResourceInstanceReplaceBecauseTainted: return ReasonTainted case plans.ResourceInstanceReplaceByRequest: return ReasonRequested case plans.ResourceInstanceReplaceBecauseCannotUpdate: return ReasonCannotUpdate case plans.ResourceInstanceReplaceByTriggers: return ReasonReplaceTriggeredBy case plans.ResourceInstanceDeleteBecauseNoResourceConfig: return ReasonDeleteBecauseNoResourceConfig case plans.ResourceInstanceDeleteBecauseWrongRepetition: return ReasonDeleteBecauseWrongRepetition case plans.ResourceInstanceDeleteBecauseCountIndex: return ReasonDeleteBecauseCountIndex case plans.ResourceInstanceDeleteBecauseEachKey: return ReasonDeleteBecauseEachKey case plans.ResourceInstanceDeleteBecauseNoModule: return ReasonDeleteBecauseNoModule case plans.ResourceInstanceReadBecauseConfigUnknown: return ReasonReadBecauseConfigUnknown case plans.ResourceInstanceDeleteBecauseNoMoveTarget: return ReasonDeleteBecauseNoMoveTarget case plans.ResourceInstanceReadBecauseDependencyPending: return ReasonReadBecauseDependencyPending case plans.ResourceInstanceReadBecauseCheckNested: return ReasonReadBecauseCheckNested default: // This should never happen, but there's no good way to guarantee // exhaustive handling of the enum, so a generic fall back is better // than a misleading result or a panic return ReasonUnknown } }