provider/template: Fix panic in cloudinit config

Fixes an uncaught panic during an interface cast in the `template_cloudinit_config` data source.

Fixes: #13572

```
$ make test TEST=./builtin/providers/template TESTARGS="-v -run=TestRender_handlePanic"
==> Checking that code complies with gofmt requirements...
==> Checking AWS provider for unchecked errors...
==> NOTE: at this time we only look for uncheck errors in the AWS package
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/04/12 10:46:33 Generated command/internal_plugin_list.go
go test -i ./builtin/providers/template || exit 1
echo ./builtin/providers/template | \
                xargs -t -n4 go test -v -run=TestRender_handlePanic -timeout=60s -parallel=4
go test -v -run=TestRender_handlePanic -timeout=60s -parallel=4 ./builtin/providers/template
=== RUN   TestRender_handlePanic
--- PASS: TestRender_handlePanic (0.00s)
PASS
ok      github.com/hashicorp/terraform/builtin/providers/template       0.028s
```
This commit is contained in:
Jake Champlin 2017-04-12 10:48:53 -04:00
parent f1666b46e6
commit 53fe7c2293
No known key found for this signature in database
GPG Key ID: DC31F41958EF4AC2
2 changed files with 34 additions and 18 deletions

View File

@ -19,41 +19,41 @@ func dataSourceCloudinitConfig() *schema.Resource {
Read: dataSourceCloudinitConfigRead, Read: dataSourceCloudinitConfigRead,
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"part": &schema.Schema{ "part": {
Type: schema.TypeList, Type: schema.TypeList,
Required: true, Required: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"content_type": &schema.Schema{ "content_type": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
"content": &schema.Schema{ "content": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
}, },
"filename": &schema.Schema{ "filename": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
"merge_type": &schema.Schema{ "merge_type": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
}, },
}, },
}, },
"gzip": &schema.Schema{ "gzip": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: true, Default: true,
}, },
"base64_encode": &schema.Schema{ "base64_encode": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: true, Default: true,
}, },
"rendered": &schema.Schema{ "rendered": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
Description: "rendered cloudinit configuration", Description: "rendered cloudinit configuration",
@ -84,7 +84,10 @@ func renderCloudinitConfig(d *schema.ResourceData) (string, error) {
cloudInitParts := make(cloudInitParts, len(partsValue.([]interface{}))) cloudInitParts := make(cloudInitParts, len(partsValue.([]interface{})))
for i, v := range partsValue.([]interface{}) { for i, v := range partsValue.([]interface{}) {
p := v.(map[string]interface{}) p, castOk := v.(map[string]interface{})
if !castOk {
return "", fmt.Errorf("Unable to parse parts in cloudinit resource declaration")
}
part := cloudInitPart{} part := cloudInitPart{}
if p, ok := p["content_type"]; ok { if p, ok := p["content_type"]; ok {

View File

@ -3,6 +3,8 @@ package template
import ( import (
"testing" "testing"
"regexp"
r "github.com/hashicorp/terraform/helper/resource" r "github.com/hashicorp/terraform/helper/resource"
) )
@ -58,7 +60,7 @@ func TestRender(t *testing.T) {
r.UnitTest(t, r.TestCase{ r.UnitTest(t, r.TestCase{
Providers: testProviders, Providers: testProviders,
Steps: []r.TestStep{ Steps: []r.TestStep{
r.TestStep{ {
Config: tt.ResourceBlock, Config: tt.ResourceBlock,
Check: r.ComposeTestCheckFunc( Check: r.ComposeTestCheckFunc(
r.TestCheckResourceAttr("data.template_cloudinit_config.foo", "rendered", tt.Expected), r.TestCheckResourceAttr("data.template_cloudinit_config.foo", "rendered", tt.Expected),
@ -69,12 +71,23 @@ func TestRender(t *testing.T) {
} }
} }
var testCloudInitConfig_basic = ` // From GH-13572, Correctly handle panic on a misconfigured cloudinit part
data "template_cloudinit_config" "config" { func TestRender_handlePanic(t *testing.T) {
part { r.UnitTest(t, r.TestCase{
content_type = "text/x-shellscript" Providers: testProviders,
content = "baz" Steps: []r.TestStep{
} {
}` Config: testCloudInitConfig_misconfiguredParts,
ExpectError: regexp.MustCompile("Unable to parse parts in cloudinit resource declaration"),
},
},
})
}
var testCloudInitConfig_basic_expected = `Content-Type: multipart/mixed; boundary=\"MIMEBOUNDARY\"\nMIME-Version: 1.0\r\n--MIMEBOUNDARY\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/x-shellscript\r\nMime-Version: 1.0\r\n\r\nbaz\r\n--MIMEBOUNDARY--\r\n` var testCloudInitConfig_misconfiguredParts = `
data "template_cloudinit_config" "foo" {
part {
content = ""
}
}
`