From 7e5eeb22684f5db9e2220818541aa8181fe699a1 Mon Sep 17 00:00:00 2001 From: Jake Champlin Date: Mon, 1 May 2017 16:48:42 -0400 Subject: [PATCH] provisioner/remote-exec: Fix panic from remote_exec provisioner Fixes panic on `nil` values of `inline` and `scripts` from improper interface casts. Fixes: #13970 --- .../remote-exec/resource_provisioner.go | 24 +++++++++--- .../remote-exec/resource_provisioner_test.go | 37 +++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/builtin/provisioners/remote-exec/resource_provisioner.go b/builtin/provisioners/remote-exec/resource_provisioner.go index 248ce5d5f..7dd86daf0 100644 --- a/builtin/provisioners/remote-exec/resource_provisioner.go +++ b/builtin/provisioners/remote-exec/resource_provisioner.go @@ -22,7 +22,7 @@ import ( func Provisioner() terraform.ResourceProvisioner { return &schema.Provisioner{ Schema: map[string]*schema.Schema{ - "inline": &schema.Schema{ + "inline": { Type: schema.TypeList, Elem: &schema.Schema{Type: schema.TypeString}, PromoteSingle: true, @@ -30,13 +30,13 @@ func Provisioner() terraform.ResourceProvisioner { ConflictsWith: []string{"script", "scripts"}, }, - "script": &schema.Schema{ + "script": { Type: schema.TypeString, Optional: true, ConflictsWith: []string{"inline", "scripts"}, }, - "scripts": &schema.Schema{ + "scripts": { Type: schema.TypeList, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, @@ -81,7 +81,11 @@ func applyFn(ctx context.Context) error { func generateScripts(d *schema.ResourceData) ([]string, error) { var lines []string for _, l := range d.Get("inline").([]interface{}) { - lines = append(lines, l.(string)) + line, ok := l.(string) + if !ok { + return nil, fmt.Errorf("Error parsing %v as a string", l) + } + lines = append(lines, line) } lines = append(lines, "") @@ -109,12 +113,20 @@ func collectScripts(d *schema.ResourceData) ([]io.ReadCloser, error) { // Collect scripts var scripts []string if script, ok := d.GetOk("script"); ok { - scripts = append(scripts, script.(string)) + scr, ok := script.(string) + if !ok { + return nil, fmt.Errorf("Error parsing script %v as string", script) + } + scripts = append(scripts, scr) } if scriptList, ok := d.GetOk("scripts"); ok { for _, script := range scriptList.([]interface{}) { - scripts = append(scripts, script.(string)) + scr, ok := script.(string) + if !ok { + return nil, fmt.Errorf("Error parsing script %v as string", script) + } + scripts = append(scripts, scr) } } diff --git a/builtin/provisioners/remote-exec/resource_provisioner_test.go b/builtin/provisioners/remote-exec/resource_provisioner_test.go index 69e5e9cdf..aa69cad61 100644 --- a/builtin/provisioners/remote-exec/resource_provisioner_test.go +++ b/builtin/provisioners/remote-exec/resource_provisioner_test.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "strings" + "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" @@ -71,6 +73,23 @@ func TestResourceProvider_generateScript(t *testing.T) { } } +func TestResourceProvider_generateScriptEmptyInline(t *testing.T) { + p := Provisioner().(*schema.Provisioner) + conf := map[string]interface{}{ + "inline": []interface{}{""}, + } + + _, err := generateScripts(schema.TestResourceDataRaw( + t, p.Schema, conf)) + if err == nil { + t.Fatal("expected error, got none") + } + + if !strings.Contains(err.Error(), "Error parsing") { + t.Fatalf("expected parsing error, got: %s", err) + } +} + func TestResourceProvider_CollectScripts_inline(t *testing.T) { p := Provisioner().(*schema.Provisioner) conf := map[string]interface{}{ @@ -162,6 +181,24 @@ func TestResourceProvider_CollectScripts_scripts(t *testing.T) { } } +func TestResourceProvider_CollectScripts_scriptsEmpty(t *testing.T) { + p := Provisioner().(*schema.Provisioner) + conf := map[string]interface{}{ + "scripts": []interface{}{""}, + } + + _, err := collectScripts(schema.TestResourceDataRaw( + t, p.Schema, conf)) + + if err == nil { + t.Fatal("expected error") + } + + if !strings.Contains(err.Error(), "Error parsing") { + t.Fatalf("Expected parsing error, got: %s", err) + } +} + func TestRetryFunc(t *testing.T) { // succeed on the third try errs := []error{io.EOF, &net.OpError{Err: errors.New("ERROR")}, nil}