mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Dereference attributes during filtering to avoid schema cache altering (#2468)
Signed-off-by: yottta <andrei.ciobanu@opentofu.org>
This commit is contained in:
parent
60fdd359d5
commit
22a42d87ab
@ -29,6 +29,7 @@ BUG FIXES:
|
||||
- Fix the error message when default value of a complex variable is containing a wrong type ([2394](https://github.com/opentofu/opentofu/issues/2394))
|
||||
- Fix the way OpenTofu downloads a module that is sourced from a GitHub branch containing slashes in the name. ([2396](https://github.com/opentofu/opentofu/issues/2396))
|
||||
- `pg` backend doesn't fail on workspace creation for paralel runs, when the database is shared across multiple projects. ([#2411](https://github.com/opentofu/opentofu/pull/2411))
|
||||
- Generating an OpenTofu configuration from an `import` block that is referencing a resource with nested attributes now works correctly, instead of giving an error that the nested computed attribute is required. ([2372](https://github.com/opentofu/opentofu/issues/2372))
|
||||
|
||||
## Previous Releases
|
||||
|
||||
|
@ -50,12 +50,15 @@ func (b *Block) Filter(filterAttribute FilterT[*Attribute], filterBlock FilterT[
|
||||
ret.Attributes = make(map[string]*Attribute, len(b.Attributes))
|
||||
}
|
||||
for name, attrS := range b.Attributes {
|
||||
if filterAttribute == nil || !filterAttribute(name, attrS) {
|
||||
ret.Attributes[name] = attrS
|
||||
// Copy the attributes of the block. Otherwise, if the filterNestedType is filtering out some attributes,
|
||||
// the underlying schema is getting altered too, rendering the providers.SchemaCache invalid.
|
||||
attr := *attrS
|
||||
if filterAttribute == nil || !filterAttribute(name, &attr) {
|
||||
ret.Attributes[name] = &attr
|
||||
}
|
||||
|
||||
if attrS.NestedType != nil {
|
||||
ret.Attributes[name].NestedType = filterNestedType(attrS.NestedType, filterAttribute)
|
||||
if attr.NestedType != nil {
|
||||
ret.Attributes[name].NestedType = filterNestedType((&attr).NestedType, filterAttribute)
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,10 +91,13 @@ func filterNestedType(obj *Object, filterAttribute FilterT[*Attribute]) *Object
|
||||
}
|
||||
|
||||
for name, attrS := range obj.Attributes {
|
||||
if filterAttribute == nil || !filterAttribute(name, attrS) {
|
||||
ret.Attributes[name] = attrS
|
||||
if attrS.NestedType != nil {
|
||||
ret.Attributes[name].NestedType = filterNestedType(attrS.NestedType, filterAttribute)
|
||||
// Copy the attributes of the block. Otherwise, if the filterNestedType is filtering out some attributes,
|
||||
// the underlying schema is getting altered too, rendering the providers.SchemaCache invalid.
|
||||
attr := *attrS
|
||||
if filterAttribute == nil || !filterAttribute(name, &attr) {
|
||||
ret.Attributes[name] = &attr
|
||||
if attr.NestedType != nil {
|
||||
ret.Attributes[name].NestedType = filterNestedType(attr.NestedType, filterAttribute)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,10 +8,9 @@ package configschema
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
@ -270,14 +269,108 @@ func TestFilter(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"filter_computed_from_optional_block": {
|
||||
schema: &Block{
|
||||
Attributes: map[string]*Attribute{
|
||||
"id": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
},
|
||||
"nested_val": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
NestedType: &Object{
|
||||
Attributes: map[string]*Attribute{
|
||||
"child_computed": {
|
||||
Type: cty.String,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
filterAttribute: FilterReadOnlyAttribute,
|
||||
filterBlock: FilterDeprecatedBlock,
|
||||
want: &Block{
|
||||
Attributes: map[string]*Attribute{
|
||||
"nested_val": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
NestedType: &Object{
|
||||
Attributes: map[string]*Attribute{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
schemaBeforeFilter := cloneBlock(tc.schema)
|
||||
got := tc.schema.Filter(tc.filterAttribute, tc.filterBlock)
|
||||
if !cmp.Equal(got, tc.want, cmp.Comparer(cty.Type.Equals), cmpopts.EquateEmpty()) {
|
||||
t.Fatal(cmp.Diff(got, tc.want, cmp.Comparer(cty.Type.Equals), cmpopts.EquateEmpty()))
|
||||
}
|
||||
if !cmp.Equal(schemaBeforeFilter, tc.schema, cmp.Comparer(cty.Type.Equals), cmpopts.EquateEmpty()) {
|
||||
t.Fatal("before and after schema differ. the filtering function alters the actual schema", cmp.Diff(schemaBeforeFilter, tc.schema, cmp.Comparer(cty.Type.Equals), cmpopts.EquateEmpty()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func cloneBlock(in *Block) *Block {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := Block{
|
||||
Attributes: make(map[string]*Attribute, len(in.Attributes)),
|
||||
BlockTypes: make(map[string]*NestedBlock, len(in.BlockTypes)),
|
||||
Description: in.Description,
|
||||
DescriptionKind: in.DescriptionKind,
|
||||
Deprecated: in.Deprecated,
|
||||
}
|
||||
for k, v := range in.Attributes {
|
||||
out.Attributes[k] = cloneAttribute(v)
|
||||
}
|
||||
for k, v := range in.BlockTypes {
|
||||
out.BlockTypes[k] = cloneNestedBlock(v)
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func cloneNestedBlock(in *NestedBlock) *NestedBlock {
|
||||
bl := cloneBlock(&in.Block)
|
||||
out := &NestedBlock{
|
||||
Block: *bl,
|
||||
Nesting: in.Nesting,
|
||||
MinItems: in.MinItems,
|
||||
MaxItems: in.MaxItems,
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func cloneAttribute(in *Attribute) *Attribute {
|
||||
out := &Attribute{
|
||||
Type: in.Type,
|
||||
NestedType: nil, // handled later
|
||||
Description: in.Description,
|
||||
DescriptionKind: in.DescriptionKind,
|
||||
Required: in.Required,
|
||||
Optional: in.Optional,
|
||||
Computed: in.Computed,
|
||||
Sensitive: in.Sensitive,
|
||||
Deprecated: in.Deprecated,
|
||||
}
|
||||
if in.NestedType != nil {
|
||||
out.NestedType = &Object{
|
||||
Attributes: make(map[string]*Attribute, len(in.NestedType.Attributes)),
|
||||
Nesting: in.NestedType.Nesting,
|
||||
}
|
||||
for k, v := range in.NestedType.Attributes {
|
||||
out.NestedType.Attributes[k] = cloneAttribute(v)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user