Fix all unknown block not outputted (#1948)

Signed-off-by: buraksenn <buraksenb@gmail.com>
This commit is contained in:
Burak Şen
2024-09-17 16:49:33 +03:00
committed by GitHub
parent 2091c96984
commit 854c49e04b
3 changed files with 106 additions and 21 deletions

View File

@@ -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
}

View File

@@ -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{}

View File

@@ -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{})