Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skip FixUpBlockAttrs when we can detect types from a new SDK #29624

Merged
merged 2 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions internal/lang/blocktoattr/fixup.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package blocktoattr

import (
"log"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/terraform/internal/configs/configschema"
Expand All @@ -12,6 +14,10 @@ import (
// type in the schema to be written with HCL block syntax as multiple nested
// blocks with the attribute name as the block type.
//
// The fixup is only applied in the absence of structural attribute types. The
// presence of these types indicate the use of a provider which does not
// support mapping blocks to attributes.
//
// This partially restores some of the block/attribute confusion from HCL 1
// so that existing patterns that depended on that confusion can continue to
// be used in the short term while we settle on a longer-term strategy.
Expand All @@ -28,13 +34,62 @@ func FixUpBlockAttrs(body hcl.Body, schema *configschema.Block) hcl.Body {
schema = &configschema.Block{}
}

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 &fixupBody{
original: body,
schema: schema,
names: ambiguousNames(schema),
}
}

// skipFixup detects any use of Attribute.NestedType, or Types which could not
// be generate by the legacy SDK when taking SchemaConfigModeAttr into account.
func skipFixup(schema *configschema.Block) bool {
for _, attr := range schema.Attributes {
if attr.NestedType != nil {
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 {
if skipFixup(&block.Block) {
return true
}
}

return false
}

type fixupBody struct {
original hcl.Body
schema *configschema.Block
Expand Down
61 changes: 61 additions & 0 deletions internal/lang/blocktoattr/fixup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,67 @@ container {
}),
wantErrs: true,
},
"no fixup allowed with NestedType": {
src: `
container {
foo = "one"
}
`,
schema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"container": {
NestedType: &configschema.Object{
Nesting: configschema.NestingList,
Attributes: map[string]*configschema.Attribute{
"foo": {
Type: 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,
},
"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{
Expand Down