mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-25 10:00:44 -05:00
Fix all unknown block not outputted (#1948)
Signed-off-by: buraksenn <buraksenb@gmail.com>
This commit is contained in:
@@ -70,45 +70,53 @@ func ComputeDiffForBlock(change structured.Change, block *jsonprovider.Block) co
|
||||
}
|
||||
|
||||
for key, blockType := range block.BlockTypes {
|
||||
childValue := blockValue.GetChild(key)
|
||||
childChange := blockValue.GetChild(key)
|
||||
|
||||
if !childValue.RelevantAttributes.MatchesPartial() {
|
||||
if !childChange.RelevantAttributes.MatchesPartial() {
|
||||
// Mark non-relevant attributes as unchanged.
|
||||
childValue = childValue.AsNoOp()
|
||||
childChange = childChange.AsNoOp()
|
||||
}
|
||||
|
||||
beforeSensitive := childValue.IsBeforeSensitive()
|
||||
afterSensitive := childValue.IsAfterSensitive()
|
||||
forcesReplacement := childValue.ReplacePaths.Matches()
|
||||
beforeSensitive := childChange.IsBeforeSensitive()
|
||||
afterSensitive := childChange.IsAfterSensitive()
|
||||
forcesReplacement := childChange.ReplacePaths.Matches()
|
||||
|
||||
if diff, ok := checkForUnknownBlock(childChange, block); ok {
|
||||
if diff.Action == plans.NoOp && childChange.Before == nil && childChange.After == nil {
|
||||
continue
|
||||
}
|
||||
blocks.AddSingleBlock(key, diff, forcesReplacement, beforeSensitive, afterSensitive)
|
||||
continue
|
||||
}
|
||||
|
||||
switch NestingMode(blockType.NestingMode) {
|
||||
case nestingModeSet:
|
||||
diffs, action := computeBlockDiffsAsSet(childValue, blockType.Block)
|
||||
if action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
|
||||
diffs, action := computeBlockDiffsAsSet(childChange, blockType.Block)
|
||||
if action == plans.NoOp && childChange.Before == nil && childChange.After == nil {
|
||||
// Don't record nil values in blocks.
|
||||
continue
|
||||
}
|
||||
blocks.AddAllSetBlock(key, diffs, forcesReplacement, beforeSensitive, afterSensitive)
|
||||
current = collections.CompareActions(current, action)
|
||||
case nestingModeList:
|
||||
diffs, action := computeBlockDiffsAsList(childValue, blockType.Block)
|
||||
if action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
|
||||
diffs, action := computeBlockDiffsAsList(childChange, blockType.Block)
|
||||
if action == plans.NoOp && childChange.Before == nil && childChange.After == nil {
|
||||
// Don't record nil values in blocks.
|
||||
continue
|
||||
}
|
||||
blocks.AddAllListBlock(key, diffs, forcesReplacement, beforeSensitive, afterSensitive)
|
||||
current = collections.CompareActions(current, action)
|
||||
case nestingModeMap:
|
||||
diffs, action := computeBlockDiffsAsMap(childValue, blockType.Block)
|
||||
if action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
|
||||
diffs, action := computeBlockDiffsAsMap(childChange, blockType.Block)
|
||||
if action == plans.NoOp && childChange.Before == nil && childChange.After == nil {
|
||||
// Don't record nil values in blocks.
|
||||
continue
|
||||
}
|
||||
blocks.AddAllMapBlocks(key, diffs, forcesReplacement, beforeSensitive, afterSensitive)
|
||||
current = collections.CompareActions(current, action)
|
||||
case nestingModeSingle, nestingModeGroup:
|
||||
diff := ComputeDiffForBlock(childValue, blockType.Block)
|
||||
if diff.Action == plans.NoOp && childValue.Before == nil && childValue.After == nil {
|
||||
diff := ComputeDiffForBlock(childChange, blockType.Block)
|
||||
if diff.Action == plans.NoOp && childChange.Before == nil && childChange.After == nil {
|
||||
// Don't record nil values in blocks.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1576,7 +1576,6 @@ func TestValue_Outputs(t *testing.T) {
|
||||
}
|
||||
|
||||
for name, tc := range tcs {
|
||||
|
||||
// Let's set some default values on the input.
|
||||
if tc.input.RelevantAttributes == nil {
|
||||
tc.input.RelevantAttributes = attribute_path.AlwaysMatcher()
|
||||
@@ -2191,7 +2190,6 @@ func TestValue_CollectionAttributes(t *testing.T) {
|
||||
}
|
||||
|
||||
for name, tc := range tcs {
|
||||
|
||||
// Let's set some default values on the input.
|
||||
if tc.input.RelevantAttributes == nil {
|
||||
tc.input.RelevantAttributes = attribute_path.AlwaysMatcher()
|
||||
@@ -2853,6 +2851,90 @@ func TestSpecificCases(t *testing.T) {
|
||||
}, plans.Update, false),
|
||||
}, nil, nil, nil, nil, plans.Update, false),
|
||||
},
|
||||
// Following tests are from issue 1805. https://github.com/opentofu/opentofu/issues/1805.
|
||||
// The issue is about handling unknown dynamic nested blocks. In these cases unknown nested blocks are
|
||||
// not shown at all but they should be listed as unknown in the diff.
|
||||
"issues/1805/create_with_unknown_dynamic_nested_block": {
|
||||
input: structured.Change{
|
||||
Before: nil,
|
||||
After: map[string]interface{}{
|
||||
"attribute_one": "test",
|
||||
},
|
||||
Unknown: map[string]interface{}{
|
||||
"nested_unknown_block": true,
|
||||
},
|
||||
ReplacePaths: &attribute_path.PathMatcher{},
|
||||
RelevantAttributes: attribute_path.AlwaysMatcher(),
|
||||
},
|
||||
block: &jsonprovider.Block{
|
||||
Attributes: map[string]*jsonprovider.Attribute{
|
||||
"attribute_one": {
|
||||
AttributeType: unmarshalType(t, cty.String),
|
||||
},
|
||||
},
|
||||
BlockTypes: map[string]*jsonprovider.BlockType{
|
||||
"nested_unknown_block": {
|
||||
Block: &jsonprovider.Block{
|
||||
Attributes: map[string]*jsonprovider.Attribute{
|
||||
"attribute_two": {
|
||||
AttributeType: unmarshalType(t, cty.String),
|
||||
},
|
||||
},
|
||||
},
|
||||
NestingMode: "single",
|
||||
},
|
||||
},
|
||||
},
|
||||
validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
|
||||
"attribute_one": renderers.ValidatePrimitive(nil, "test", plans.Create, false),
|
||||
}, map[string]renderers.ValidateDiffFunction{
|
||||
"nested_unknown_block": renderers.ValidateUnknown(nil, plans.Create, false),
|
||||
}, nil, nil, nil, plans.Create, false),
|
||||
},
|
||||
"issues/1805/update_with_unknown_dynamic_nested_block": {
|
||||
input: structured.Change{
|
||||
Before: map[string]interface{}{
|
||||
"attribute_one": "before_value_attr_1",
|
||||
"attribute_two": "before_value_attr_2",
|
||||
},
|
||||
After: map[string]interface{}{
|
||||
"attribute_one": "after_value_attr_1",
|
||||
},
|
||||
Unknown: map[string]interface{}{
|
||||
"nested_unknown_block": true,
|
||||
},
|
||||
ReplacePaths: &attribute_path.PathMatcher{},
|
||||
RelevantAttributes: attribute_path.AlwaysMatcher(),
|
||||
},
|
||||
block: &jsonprovider.Block{
|
||||
Attributes: map[string]*jsonprovider.Attribute{
|
||||
"attribute_one": {
|
||||
AttributeType: unmarshalType(t, cty.String),
|
||||
},
|
||||
"attribute_two": {
|
||||
AttributeType: unmarshalType(t, cty.String),
|
||||
},
|
||||
},
|
||||
BlockTypes: map[string]*jsonprovider.BlockType{
|
||||
"nested_unknown_block": {
|
||||
Block: &jsonprovider.Block{
|
||||
Attributes: map[string]*jsonprovider.Attribute{
|
||||
"attribute_two": {
|
||||
AttributeType: unmarshalType(t, cty.String),
|
||||
},
|
||||
},
|
||||
},
|
||||
NestingMode: "single",
|
||||
},
|
||||
},
|
||||
},
|
||||
validate: renderers.ValidateBlock(map[string]renderers.ValidateDiffFunction{
|
||||
"attribute_one": renderers.ValidatePrimitive("before_value_attr_1", "after_value_attr_1", plans.Update, false),
|
||||
"attribute_two": renderers.ValidatePrimitive("before_value_attr_2", nil, plans.Delete, false),
|
||||
}, map[string]renderers.ValidateDiffFunction{
|
||||
"nested_unknown_block": renderers.ValidateUnknown(nil, plans.Create, false),
|
||||
}, nil, nil, nil, plans.Update, false),
|
||||
},
|
||||
}
|
||||
for name, tc := range tcs {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
@@ -2880,7 +2962,6 @@ func wrapChangeInSlice(input structured.Change) structured.Change {
|
||||
case nil:
|
||||
if set, ok := unknown.(bool); (set && ok) || explicit {
|
||||
return []interface{}{nil}
|
||||
|
||||
}
|
||||
return []interface{}{}
|
||||
default:
|
||||
@@ -2911,7 +2992,6 @@ func wrapChangeInMap(input structured.Change) structured.Change {
|
||||
}
|
||||
|
||||
func wrapChange(input structured.Change, step interface{}, wrap func(interface{}, interface{}, bool) interface{}) structured.Change {
|
||||
|
||||
replacePaths := &attribute_path.PathMatcher{}
|
||||
for _, path := range input.ReplacePaths.(*attribute_path.PathMatcher).Paths {
|
||||
var updated []interface{}
|
||||
@@ -2925,7 +3005,6 @@ func wrapChange(input structured.Change, step interface{}, wrap func(interface{}
|
||||
// those as well.
|
||||
relevantAttributes := input.RelevantAttributes
|
||||
if concrete, ok := relevantAttributes.(*attribute_path.PathMatcher); ok {
|
||||
|
||||
newRelevantAttributes := &attribute_path.PathMatcher{}
|
||||
for _, path := range concrete.Paths {
|
||||
var updated []interface{}
|
||||
|
||||
@@ -24,7 +24,6 @@ func checkForUnknownType(change structured.Change, ctype cty.Type) (computed.Dif
|
||||
}
|
||||
|
||||
func checkForUnknownNestedAttribute(change structured.Change, attribute *jsonprovider.NestedType) (computed.Diff, bool) {
|
||||
|
||||
// We want our child attributes to show up as computed instead of deleted.
|
||||
// Let's populate that here.
|
||||
childUnknown := make(map[string]interface{})
|
||||
@@ -41,7 +40,6 @@ func checkForUnknownNestedAttribute(change structured.Change, attribute *jsonpro
|
||||
}
|
||||
|
||||
func checkForUnknownBlock(change structured.Change, block *jsonprovider.Block) (computed.Diff, bool) {
|
||||
|
||||
// We want our child attributes to show up as computed instead of deleted.
|
||||
// Let's populate that here.
|
||||
childUnknown := make(map[string]interface{})
|
||||
|
||||
Reference in New Issue
Block a user