@ -687,26 +687,24 @@ func (n *NodeAbstractResourceInstance) plan(
priorVal = cty . NullVal ( schema . ImpliedType ( ) )
}
// Create an unmarked version of our config val and our prior val.
// Store the paths for the config val to re-markafter
// we've sent things over the wire.
unmarkedConfigVal , unmarkedPaths := origConfigVal . UnmarkDeepWithPaths ( )
unmarkedPriorVal , priorPaths := priorVal . UnmarkDeepWithPaths ( )
log . Printf ( "[TRACE] Re-validating config for %q" , n . Addr )
// Allow the provider to validate the final set of values.
// The config was statically validated early on, but there may have been
// unknown values which the provider could not validate at the time.
// Allow the provider to validate the final set of values. The config was
// statically validated early on, but there may have been unknown values
// which the provider could not validate at the time.
//
// TODO: It would be more correct to validate the config after
// ignore_changes has been applied, but the current implementation cannot
// exclude computed-only attributes when given the `all` option.
// we must unmark and use the original config, since the ignore_changes
// handling below needs access to the marks.
unmarkedConfigVal , _ := origConfigVal . UnmarkDeep ( )
validateResp := provider . ValidateResourceConfig (
providers . ValidateResourceConfigRequest {
TypeName : n . Addr . Resource . Resource . Type ,
Config : unmarkedConfigVal ,
} ,
)
diags = diags . Append ( validateResp . Diagnostics . InConfigBody ( config . Config , n . Addr . String ( ) ) )
if diags . HasErrors ( ) {
return plan , state , diags
@ -717,13 +715,21 @@ func (n *NodeAbstractResourceInstance) plan(
// the proposed value, the proposed value itself, and the config presented
// to the provider in the PlanResourceChange request all agree on the
// starting values.
configValIgnored , ignoreChangeDiags := n . processIgnoreChanges ( unmarkedPriorVal , unmarkedConfigVal )
// Here we operate on the marked values, so as to revert any changes to the
// marks as well as the value.
configValIgnored , ignoreChangeDiags := n . processIgnoreChanges ( priorVal , origConfigVal )
diags = diags . Append ( ignoreChangeDiags )
if ignoreChangeDiags . HasErrors ( ) {
return plan , state , diags
}
proposedNewVal := objchange . ProposedNew ( schema , unmarkedPriorVal , configValIgnored )
// Create an unmarked version of our config val and our prior val.
// Store the paths for the config val to re-mark after we've sent things
// over the wire.
unmarkedConfigVal , unmarkedPaths := configValIgnored . UnmarkDeepWithPaths ( )
unmarkedPriorVal , priorPaths := priorVal . UnmarkDeepWithPaths ( )
proposedNewVal := objchange . ProposedNew ( schema , unmarkedPriorVal , unmarkedConfigVal )
// Call pre-diff hook
diags = diags . Append ( ctx . Hook ( func ( h Hook ) ( HookAction , error ) {
@ -735,7 +741,7 @@ func (n *NodeAbstractResourceInstance) plan(
resp := provider . PlanResourceChange ( providers . PlanResourceChangeRequest {
TypeName : n . Addr . Resource . Resource . Type ,
Config : configValIgnored ,
Config : unmarkedConfigVal ,
PriorState : unmarkedPriorVal ,
ProposedNewState : proposedNewVal ,
PriorPrivate : priorPrivate ,
@ -774,7 +780,7 @@ func (n *NodeAbstractResourceInstance) plan(
return plan , state , diags
}
if errs := objchange . AssertPlanValid ( schema , unmarkedPriorVal , configValIgnored , plannedNewVal ) ; len ( errs ) > 0 {
if errs := objchange . AssertPlanValid ( schema , unmarkedPriorVal , unmarkedConfigVal , plannedNewVal ) ; len ( errs ) > 0 {
if resp . LegacyTypeSystem {
// The shimming of the old type system in the legacy SDK is not precise
// enough to pass this consistency check, so we'll give it a pass here,
@ -1085,7 +1091,7 @@ func (n *NodeAbstractResource) processIgnoreChanges(prior, config cty.Value) (ct
return config , nil
}
ignoreChanges := n . Config . Managed . IgnoreChanges
ignoreChanges := traversalsToPaths ( n . Config . Managed . IgnoreChanges )
ignoreAll := n . Config . Managed . IgnoreAllChanges
if len ( ignoreChanges ) == 0 && ! ignoreAll {
@ -1100,14 +1106,16 @@ func (n *NodeAbstractResource) processIgnoreChanges(prior, config cty.Value) (ct
return config , nil
}
return processIgnoreChangesIndividual ( prior , config , ignoreChanges )
ret , diags := processIgnoreChangesIndividual ( prior , config , ignoreChanges )
return ret , diags
}
func processIgnoreChangesIndividual ( prior , config cty . Value , ignoreChanges [ ] hcl . Traversal ) ( cty . Value , tfdiags . Diagnostics ) {
// When we walk below we will be using cty.Path values for comparison, so
// we'll convert our traversals here so we can compare more easily.
ignoreChangesPath := make ( [ ] cty . Path , len ( ignoreChange s) )
for i , traversal := range ignoreChange s {
// Convert the hcl.Traversal values we get form the configuration to the
// cty.Path values we need to operate on the cty.Values
func traversalsToPaths ( traversals [ ] hcl . Traversal ) [ ] cty . Path {
paths := make ( [ ] cty . Path , len ( traversal s) )
for i , traversal := range traversal s {
path := make ( cty . Path , len ( traversal ) )
for si , step := range traversal {
switch ts := step . ( type ) {
@ -1127,9 +1135,12 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl
panic ( fmt . Sprintf ( "unsupported traversal step %#v" , step ) )
}
}
ignoreChangesPath [ i ] = path
paths [ i ] = path
}
return paths
}
func processIgnoreChangesIndividual ( prior , config cty . Value , ignoreChangesPath [ ] cty . Path ) ( cty . Value , tfdiags . Diagnostics ) {
type ignoreChange struct {
// Path is the full path, minus any trailing map index
path cty . Path
@ -1175,8 +1186,7 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl
// here even if our ignored key doesn't change. That is OK since it
// won't cause any changes in the transformation, but allows us to skip
// breaking up the maps and checking for key existence here too.
eq := p . Equals ( c )
if ! eq . IsKnown ( ) || eq . False ( ) {
if ! p . RawEquals ( c ) {
// there a change to ignore at this path, store the prior value
ignoredValues = append ( ignoredValues , ignoreChange { icPath , p , key } )
}
@ -1205,6 +1215,10 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl
return v , nil
}
// The map values will remain as cty values, so we only need to store
// the marks from the outer map itself
v , vMarks := v . Unmark ( )
// The configMap is the current configuration value, which we will
// mutate based on the ignored paths and the prior map value.
var configMap map [ string ] cty . Value
@ -1234,11 +1248,17 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl
// return null for a key with a null value and for a non-existent
// key.
var priorMap map [ string ] cty . Value
// We need to drop the marks from the ignored map for handling. We
// don't need to store these, as we now know the ignored value is
// only within the map, not the map itself.
ignoredVal , _ := ignored . value . Unmark ( )
switch {
case ignored . value . IsNull ( ) || ignored . value . LengthInt ( ) == 0 :
case ignored . value . IsNull ( ) || ignored Val . LengthInt ( ) == 0 :
priorMap = map [ string ] cty . Value { }
default :
priorMap = ignored . value . AsValueMap ( )
priorMap = ignored Val . AsValueMap ( )
}
key := ignored . key . AsString ( )
@ -1254,11 +1274,18 @@ func processIgnoreChangesIndividual(prior, config cty.Value, ignoreChanges []hcl
}
}
var newVal cty . Value
if len ( configMap ) == 0 {
return cty . MapValEmpty ( v . Type ( ) . ElementType ( ) ) , nil
newVal = cty . MapValEmpty ( v . Type ( ) . ElementType ( ) )
} else {
newVal = cty . MapVal ( configMap )
}
if len ( vMarks ) > 0 {
newVal = v . WithMarks ( vMarks )
}
return cty . MapVal ( configMap ) , nil
return newVal , nil
} )
return ret , nil
}