json-output: Add change reasons to explain deletes

The extra feedback information for why resource instance deletion is
planned is now included in the streaming JSON UI output.

We also add an explicit case for no-op actions to switch statements in
this package to ensure exhaustiveness, for future linting.
This commit is contained in:
Alisdair McDiarmid 2021-09-24 11:18:39 -04:00
parent c8cd0b1e74
commit b699391d04
3 changed files with 34 additions and 1 deletions

View File

@ -73,6 +73,12 @@ const (
ReasonRequested ChangeReason = "requested" ReasonRequested ChangeReason = "requested"
ReasonCannotUpdate ChangeReason = "cannot_update" ReasonCannotUpdate ChangeReason = "cannot_update"
ReasonUnknown ChangeReason = "unknown" 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"
) )
func changeReason(reason plans.ResourceInstanceChangeActionReason) ChangeReason { func changeReason(reason plans.ResourceInstanceChangeActionReason) ChangeReason {
@ -85,6 +91,16 @@ func changeReason(reason plans.ResourceInstanceChangeActionReason) ChangeReason
return ReasonRequested return ReasonRequested
case plans.ResourceInstanceReplaceBecauseCannotUpdate: case plans.ResourceInstanceReplaceBecauseCannotUpdate:
return ReasonCannotUpdate return ReasonCannotUpdate
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
default: default:
// This should never happen, but there's no good way to guarantee // This should never happen, but there's no good way to guarantee
// exhaustive handling of the enum, so a generic fall back is better // exhaustive handling of the enum, so a generic fall back is better

View File

@ -314,6 +314,10 @@ func startActionVerb(action plans.Action) string {
// This is not currently possible to reach, as we receive separate // This is not currently possible to reach, as we receive separate
// passes for create and delete // passes for create and delete
return "Replacing" return "Replacing"
case plans.NoOp:
// This should never be possible: a no-op planned change should not
// be applied. We'll fall back to "Applying".
fallthrough
default: default:
return "Applying" return "Applying"
} }
@ -336,6 +340,10 @@ func progressActionVerb(action plans.Action) string {
// This is not currently possible to reach, as we receive separate // This is not currently possible to reach, as we receive separate
// passes for create and delete // passes for create and delete
return "replacing" return "replacing"
case plans.NoOp:
// This should never be possible: a no-op planned change should not
// be applied. We'll fall back to "applying".
fallthrough
default: default:
return "applying" return "applying"
} }
@ -358,6 +366,10 @@ func actionNoun(action plans.Action) string {
// This is not currently possible to reach, as we receive separate // This is not currently possible to reach, as we receive separate
// passes for create and delete // passes for create and delete
return "Replacement" return "Replacement"
case plans.NoOp:
// This should never be possible: a no-op planned change should not
// be applied. We'll fall back to "Apply".
fallthrough
default: default:
return "Apply" return "Apply"
} }

View File

@ -126,10 +126,15 @@ At the end of a plan or before an apply, Terraform will emit a `planned_change`
- `resource`: object describing the address of the resource to be changed; see [resource object](#resource-object) below for details - `resource`: object describing the address of the resource to be changed; see [resource object](#resource-object) below for details
- `previous_resource`: object describing the previous address of the resource, if this change includes a configuration-driven move - `previous_resource`: object describing the previous address of the resource, if this change includes a configuration-driven move
- `action`: the action planned to be taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete`, `move`. - `action`: the action planned to be taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete`, `move`.
- `reason`: an optional reason for the change, currently only used when the action is `replace`. Values: - `reason`: an optional reason for the change, currently only used when the action is `replace` or `delete`. Values:
- `tainted`: resource was marked as tainted - `tainted`: resource was marked as tainted
- `requested`: user requested that the resource be replaced, for example via the `-replace` plan flag - `requested`: user requested that the resource be replaced, for example via the `-replace` plan flag
- `cannot_update`: changes to configuration force the resource to be deleted and created rather than updated - `cannot_update`: changes to configuration force the resource to be deleted and created rather than updated
- `delete_because_no_resource_config`: no matching resource in configuration
- `delete_because_wrong_repetition`: resource instance key has no corresponding `count` or `for_each` in configuration
- `delete_because_count_index`: resource instance key is outside the range of the `count` argument
- `delete_because_each_key`: resource instance key is not included in the `for_each` argument
- `delete_because_no_module`: enclosing module instance is not in configuration
This message does not include details about the exact changes which caused the change to be planned. That information is available in [the JSON plan output](./json-format.html). This message does not include details about the exact changes which caused the change to be planned. That information is available in [the JSON plan output](./json-format.html).