mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-20 02:09:26 -05:00
157 lines
5.5 KiB
Go
157 lines
5.5 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package jsonentities
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/opentofu/opentofu/internal/plans"
|
|
)
|
|
|
|
func NewResourceInstanceChange(change *plans.ResourceInstanceChangeSrc) *ResourceInstanceChange {
|
|
c := &ResourceInstanceChange{
|
|
Resource: NewResourceAddr(change.Addr),
|
|
Action: ParseChangeAction(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)
|
|
}
|
|
|
|
type ChangeAction string
|
|
|
|
const (
|
|
ActionNoOp ChangeAction = "noop"
|
|
ActionMove ChangeAction = "move"
|
|
ActionCreate ChangeAction = "create"
|
|
ActionRead ChangeAction = "read"
|
|
ActionUpdate ChangeAction = "update"
|
|
ActionReplace ChangeAction = "replace"
|
|
ActionDelete ChangeAction = "delete"
|
|
ActionImport ChangeAction = "import"
|
|
ActionForget ChangeAction = "remove"
|
|
)
|
|
|
|
func ParseChangeAction(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:
|
|
return ActionReplace
|
|
case plans.Delete:
|
|
return ActionDelete
|
|
case plans.Forget:
|
|
return ActionForget
|
|
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
|
|
}
|
|
}
|