|
|
|
|
@ -791,7 +791,7 @@ func (n *NodeAbstractResourceInstance) plan(
|
|
|
|
|
plannedChange *plans.ResourceInstanceChange,
|
|
|
|
|
currentState *states.ResourceInstanceObject,
|
|
|
|
|
createBeforeDestroy bool,
|
|
|
|
|
forceReplace []addrs.AbsResourceInstance,
|
|
|
|
|
forceReplace bool,
|
|
|
|
|
) (*plans.ResourceInstanceChange, *states.ResourceInstanceObject, *providers.Deferred, instances.RepetitionData, tfdiags.Diagnostics) {
|
|
|
|
|
var diags tfdiags.Diagnostics
|
|
|
|
|
var keyData instances.RepetitionData
|
|
|
|
|
@ -2971,26 +2971,7 @@ func resourceInstancePrevRunAddr(ctx EvalContext, currentAddr addrs.AbsResourceI
|
|
|
|
|
return table.OldAddr(currentAddr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getAction(addr addrs.AbsResourceInstance, priorVal, plannedNewVal cty.Value, createBeforeDestroy bool, writeOnly cty.PathSet, forceReplace []addrs.AbsResourceInstance, reqRep cty.PathSet) (action plans.Action, actionReason plans.ResourceInstanceChangeActionReason) {
|
|
|
|
|
// The user might also ask us to force replacing a particular resource
|
|
|
|
|
// instance, regardless of whether the provider thinks it needs replacing.
|
|
|
|
|
// For example, users typically do this if they learn a particular object
|
|
|
|
|
// has become degraded in an immutable infrastructure scenario and so
|
|
|
|
|
// replacing it with a new object is a viable repair path.
|
|
|
|
|
matchedForceReplace := false
|
|
|
|
|
for _, candidateAddr := range forceReplace {
|
|
|
|
|
if candidateAddr.Equal(addr) {
|
|
|
|
|
matchedForceReplace = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For "force replace" purposes we require an exact resource instance
|
|
|
|
|
// address to match. If a user forgets to include the instance key
|
|
|
|
|
// for a multi-instance resource then it won't match here, but we
|
|
|
|
|
// have an earlier check in NodePlannableResource.Execute that should
|
|
|
|
|
// prevent us from getting here in that case.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getAction(addr addrs.AbsResourceInstance, priorVal, plannedNewVal cty.Value, createBeforeDestroy bool, writeOnly cty.PathSet, forceReplace bool, reqRep cty.PathSet) (action plans.Action, actionReason plans.ResourceInstanceChangeActionReason) {
|
|
|
|
|
// Unmark for this test for value equality.
|
|
|
|
|
eqV := plannedNewVal.Equals(priorVal)
|
|
|
|
|
eq := eqV.IsKnown() && eqV.True()
|
|
|
|
|
@ -2998,7 +2979,7 @@ func getAction(addr addrs.AbsResourceInstance, priorVal, plannedNewVal cty.Value
|
|
|
|
|
switch {
|
|
|
|
|
case priorVal.IsNull():
|
|
|
|
|
action = plans.Create
|
|
|
|
|
case matchedForceReplace || !reqRep.Empty() || !writeOnly.Intersection(reqRep).Empty():
|
|
|
|
|
case forceReplace || !reqRep.Empty() || !writeOnly.Intersection(reqRep).Empty():
|
|
|
|
|
// If the user "forced replace" of this instance of if there are any
|
|
|
|
|
// "requires replace" paths left _after our filtering above_ then this
|
|
|
|
|
// is a replace action.
|
|
|
|
|
@ -3008,12 +2989,12 @@ func getAction(addr addrs.AbsResourceInstance, priorVal, plannedNewVal cty.Value
|
|
|
|
|
action = plans.DeleteThenCreate
|
|
|
|
|
}
|
|
|
|
|
switch {
|
|
|
|
|
case matchedForceReplace:
|
|
|
|
|
case forceReplace:
|
|
|
|
|
actionReason = plans.ResourceInstanceReplaceByRequest
|
|
|
|
|
case !reqRep.Empty():
|
|
|
|
|
actionReason = plans.ResourceInstanceReplaceBecauseCannotUpdate
|
|
|
|
|
}
|
|
|
|
|
case eq && !matchedForceReplace:
|
|
|
|
|
case eq && !forceReplace:
|
|
|
|
|
action = plans.NoOp
|
|
|
|
|
default:
|
|
|
|
|
action = plans.Update
|
|
|
|
|
|