diff --git a/plans/objchange/objchange.go b/plans/objchange/objchange.go index ed0f4ba5ee..18a8828467 100644 --- a/plans/objchange/objchange.go +++ b/plans/objchange/objchange.go @@ -177,7 +177,7 @@ func proposedNewObject(schema *configschema.Block, prior, config cty.Value) cty. atys := configV.Type().AttributeTypes() for name := range atys { configEV := configV.GetAttr(name) - if !priorV.Type().HasAttribute(name) { + if !priorV.IsKnown() || priorV.IsNull() || !priorV.Type().HasAttribute(name) { // If there is no corresponding prior element then // we just take the config value as-is. newVals[name] = configEV diff --git a/plans/objchange/plan_valid.go b/plans/objchange/plan_valid.go index 308c47f59d..dd7d7ce217 100644 --- a/plans/objchange/plan_valid.go +++ b/plans/objchange/plan_valid.go @@ -182,7 +182,7 @@ func assertPlanValid(schema *configschema.Block, priorState, config, plannedStat configEV := configV.Index(idx) priorEV := cty.NullVal(blockS.ImpliedType()) if !priorV.IsNull() && priorV.HasIndex(idx).True() { - priorEV = priorV.GetAttr(k) + priorEV = priorV.Index(idx) } moreErrs := assertPlanValid(&blockS.Block, priorEV, configEV, plannedEV, path) errs = append(errs, moreErrs...) diff --git a/plans/objchange/plan_valid_test.go b/plans/objchange/plan_valid_test.go index ff01881b5a..cc41d694a3 100644 --- a/plans/objchange/plan_valid_test.go +++ b/plans/objchange/plan_valid_test.go @@ -312,6 +312,45 @@ func TestAssertPlanValid(t *testing.T) { }), nil, }, + "nested map, normal update": { + &configschema.Block{ + BlockTypes: map[string]*configschema.NestedBlock{ + "b": { + Nesting: configschema.NestingMap, + Block: configschema.Block{ + Attributes: map[string]*configschema.Attribute{ + "c": { + Type: cty.String, + Optional: true, + }, + }, + }, + }, + }, + }, + cty.ObjectVal(map[string]cty.Value{ + "b": cty.MapVal(map[string]cty.Value{ + "boop": cty.ObjectVal(map[string]cty.Value{ + "c": cty.StringVal("hello"), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "b": cty.MapVal(map[string]cty.Value{ + "boop": cty.ObjectVal(map[string]cty.Value{ + "c": cty.StringVal("howdy"), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "b": cty.MapVal(map[string]cty.Value{ + "boop": cty.ObjectVal(map[string]cty.Value{ + "c": cty.StringVal("howdy"), + }), + }), + }), + nil, + }, // Nested block collections are never null "nested list, null in plan": {