@ -715,6 +715,13 @@ func (n *NodeAbstractResourceInstance) plan(
return plan , state , keyData , diags // failed preconditions prevent further evaluation
}
// If we have a previous plan and the action was a noop, then the only
// reason we're in this method was to evaluate the preconditions. There's
// no need to re-plan this resource.
if plannedChange != nil && plannedChange . Action == plans . NoOp {
return plannedChange , currentState . DeepCopy ( ) , keyData , diags
}
origConfigVal , _ , configDiags := ctx . EvaluateBlock ( config . Config , schema , nil , keyData )
diags = diags . Append ( configDiags )
if configDiags . HasErrors ( ) {
@ -2059,44 +2066,38 @@ func (n *NodeAbstractResourceInstance) evalDestroyProvisionerConfig(ctx EvalCont
}
// apply accepts an applyConfig, instead of using n.Config, so destroy plans can
// send a nil config. Most of the errors generated in apply are returned as
// diagnostics, but if provider.ApplyResourceChange itself fails, that error is
// returned as an error and nil diags are returned.
// send a nil config. The keyData information can be empty if the config is
// nil, since it is only used to evaluate the configuration.
func ( n * NodeAbstractResourceInstance ) apply (
ctx EvalContext ,
state * states . ResourceInstanceObject ,
change * plans . ResourceInstanceChange ,
applyConfig * configs . Resource ,
createBeforeDestroy bool ) ( * states . ResourceInstanceObject , instances . RepetitionData , tfdiags . Diagnostics ) {
keyData instances . RepetitionData ,
createBeforeDestroy bool ) ( * states . ResourceInstanceObject , tfdiags . Diagnostics ) {
var diags tfdiags . Diagnostics
var keyData instances . RepetitionData
if state == nil {
state = & states . ResourceInstanceObject { }
}
if applyConfig != nil {
forEach , _ := evaluateForEachExpression ( applyConfig . ForEach , ctx )
keyData = EvalDataForInstanceKey ( n . ResourceInstanceAddr ( ) . Resource . Key , forEach )
}
if change . Action == plans . NoOp {
// If this is a no-op change then we don't want to actually change
// anything, so we'll just echo back the state we were given and
// let our internal checks and updates proceed.
log . Printf ( "[TRACE] NodeAbstractResourceInstance.apply: skipping %s because it has no planned action" , n . Addr )
return state , keyData, diags
return state , diags
}
provider , providerSchema , err := getProvider ( ctx , n . ResolvedProvider )
if err != nil {
return nil , keyData, diags. Append ( err )
return nil , diags. Append ( err )
}
schema , _ := providerSchema . SchemaForResourceType ( n . Addr . Resource . Resource . Mode , n . Addr . Resource . Resource . Type )
if schema == nil {
// Should be caught during validation, so we don't bother with a pretty error here
diags = diags . Append ( fmt . Errorf ( "provider does not support resource type %q" , n . Addr . Resource . Resource . Type ) )
return nil , keyData, diags
return nil , diags
}
log . Printf ( "[INFO] Starting apply for %s" , n . Addr )
@ -2107,7 +2108,7 @@ func (n *NodeAbstractResourceInstance) apply(
configVal , _ , configDiags = ctx . EvaluateBlock ( applyConfig . Config , schema , nil , keyData )
diags = diags . Append ( configDiags )
if configDiags . HasErrors ( ) {
return nil , keyData, diags
return nil , diags
}
}
@ -2132,13 +2133,13 @@ func (n *NodeAbstractResourceInstance) apply(
strings . Join ( unknownPaths , "\n" ) ,
) ,
) )
return nil , keyData, diags
return nil , diags
}
metaConfigVal , metaDiags := n . providerMetas ( ctx )
diags = diags . Append ( metaDiags )
if diags . HasErrors ( ) {
return nil , keyData, diags
return nil , diags
}
log . Printf ( "[DEBUG] %s: applying the planned %s change" , n . Addr , change . Action )
@ -2166,7 +2167,7 @@ func (n *NodeAbstractResourceInstance) apply(
Status : state . Status ,
Value : change . After ,
}
return newState , keyData, diags
return newState , diags
}
resp := provider . ApplyResourceChange ( providers . ApplyResourceChangeRequest {
@ -2237,7 +2238,7 @@ func (n *NodeAbstractResourceInstance) apply(
// Bail early in this particular case, because an object that doesn't
// conform to the schema can't be saved in the state anyway -- the
// serializer will reject it.
return nil , keyData, diags
return nil , diags
}
// After this point we have a type-conforming result object and so we
@ -2363,7 +2364,7 @@ func (n *NodeAbstractResourceInstance) apply(
// prior state as the new value, making this effectively a no-op. If
// the item really _has_ been deleted then our next refresh will detect
// that and fix it up.
return state . DeepCopy ( ) , keyData, diags
return state . DeepCopy ( ) , diags
case diags . HasErrors ( ) && ! newVal . IsNull ( ) :
// if we have an error, make sure we restore the object status in the new state
@ -2380,7 +2381,7 @@ func (n *NodeAbstractResourceInstance) apply(
newState . Dependencies = state . Dependencies
}
return newState , keyData, diags
return newState , diags
case ! newVal . IsNull ( ) :
// Non error case with a new state
@ -2390,11 +2391,11 @@ func (n *NodeAbstractResourceInstance) apply(
Private : resp . Private ,
CreateBeforeDestroy : createBeforeDestroy ,
}
return newState , keyData, diags
return newState , diags
default :
// Non error case, were the object was deleted
return nil , keyData, diags
return nil , diags
}
}