refine the skipFixup heuristic

We can also rule out some attribute types as indicating something other
than the legacy SDK.

- Tuple types were not generated at all.
- There were no single objects types, the convention was to use a block
  list or set of length 1.
- Maps of objects were not possible to generate, since named blocks were
  not implemented.
- Nested collections were not supported, but when they were generated they
  would have primitive types.
This commit is contained in:
James Bardin 2021-09-22 15:59:25 -04:00
parent 6b4e73af48
commit 8706a18c4b
2 changed files with 64 additions and 4 deletions

View File

@ -1,6 +1,8 @@
package blocktoattr package blocktoattr
import ( import (
"log"
"github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/terraform/internal/configs/configschema" "github.com/hashicorp/terraform/internal/configs/configschema"
@ -33,6 +35,10 @@ func FixUpBlockAttrs(body hcl.Body, schema *configschema.Block) hcl.Body {
} }
if skipFixup(schema) { if skipFixup(schema) {
// we don't have any context for the resource name or type, but
// hopefully this could help locate the evaluation in the logs if there
// were a problem
log.Println("[DEBUG] skipping FixUpBlockAttrs")
return body return body
} }
@ -43,14 +49,36 @@ func FixUpBlockAttrs(body hcl.Body, schema *configschema.Block) hcl.Body {
} }
} }
// skipFixup detects any use of Attribute.NestedType. Because the fixup was // skipFixup detects any use of Attribute.NestedType, or Types which could not
// only supported for the legacy SDK, there is no situation where structural // be generate by the legacy SDK when taking SchemaConfigModeAttr into account.
// attributes are used where the fixup is expected.
func skipFixup(schema *configschema.Block) bool { func skipFixup(schema *configschema.Block) bool {
for _, attr := range schema.Attributes { for _, attr := range schema.Attributes {
if attr.NestedType != nil { if attr.NestedType != nil {
return true return true
} }
ty := attr.Type
// Lists and sets of objects could be generated by
// SchemaConfigModeAttr, but some other combinations can be ruled out.
// Tuples and objects could not be generated at all.
if ty.IsTupleType() || ty.IsObjectType() {
return true
}
// A map of objects was not possible.
if ty.IsMapType() && ty.ElementType().IsObjectType() {
return true
}
// Nested collections were not really supported, but could be generated
// with string types (though we conservatively limit this to primitive types)
if ty.IsCollectionType() {
ety := ty.ElementType()
if ety.IsCollectionType() && !ety.ElementType().IsPrimitiveType() {
return true
}
}
} }
for _, block := range schema.BlockTypes { for _, block := range schema.BlockTypes {

View File

@ -400,7 +400,7 @@ container {
}), }),
wantErrs: true, wantErrs: true,
}, },
"no fixup allowed": { "no fixup allowed with NestedType": {
src: ` src: `
container { container {
foo = "one" foo = "one"
@ -429,6 +429,38 @@ container {
}), }),
wantErrs: true, wantErrs: true,
}, },
"no fixup allowed new types": {
src: `
container {
foo = "one"
}
`,
schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
// This could be a ConfigModeAttr fixup
"container": {
Type: cty.List(cty.Object(map[string]cty.Type{
"foo": cty.String,
})),
},
// But the presence of this type means it must have been
// declared by a new SDK
"new_type": {
Type: cty.Object(map[string]cty.Type{
"boo": cty.String,
}),
},
},
},
want: cty.ObjectVal(map[string]cty.Value{
"container": cty.NullVal(cty.List(
cty.Object(map[string]cty.Type{
"foo": cty.String,
}),
)),
}),
wantErrs: true,
},
} }
ctx := &hcl.EvalContext{ ctx := &hcl.EvalContext{