provisioner/remote-exec: fail on first inline script with bad exit code (#11155)
The provisioner collected all inline commands into a single script which meant only the exit code of the last command was actually checked for an error.
This commit is contained in:
parent
2f520c0e64
commit
d2047d714e
|
@ -7,7 +7,6 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/communicator"
|
||||
|
@ -63,32 +62,30 @@ func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string
|
|||
return
|
||||
}
|
||||
|
||||
// generateScript takes the configuration and creates a script to be executed
|
||||
// from the inline configs
|
||||
func (p *ResourceProvisioner) generateScript(c *terraform.ResourceConfig) (string, error) {
|
||||
var lines []string
|
||||
// generateScripts takes the configuration and creates a script from each inline config
|
||||
func (p *ResourceProvisioner) generateScripts(c *terraform.ResourceConfig) ([]string, error) {
|
||||
var scripts []string
|
||||
command, ok := c.Config["inline"]
|
||||
if ok {
|
||||
switch cmd := command.(type) {
|
||||
case string:
|
||||
lines = append(lines, cmd)
|
||||
scripts = append(scripts, cmd)
|
||||
case []string:
|
||||
lines = append(lines, cmd...)
|
||||
scripts = append(scripts, cmd...)
|
||||
case []interface{}:
|
||||
for _, l := range cmd {
|
||||
lStr, ok := l.(string)
|
||||
if ok {
|
||||
lines = append(lines, lStr)
|
||||
scripts = append(scripts, lStr)
|
||||
} else {
|
||||
return "", fmt.Errorf("Unsupported 'inline' type! Must be string, or list of strings.")
|
||||
return nil, fmt.Errorf("Unsupported 'inline' type! Must be string, or list of strings.")
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("Unsupported 'inline' type! Must be string, or list of strings.")
|
||||
return nil, fmt.Errorf("Unsupported 'inline' type! Must be string, or list of strings.")
|
||||
}
|
||||
}
|
||||
lines = append(lines, "")
|
||||
return strings.Join(lines, "\n"), nil
|
||||
return scripts, nil
|
||||
}
|
||||
|
||||
// collectScripts is used to collect all the scripts we need
|
||||
|
@ -97,12 +94,17 @@ func (p *ResourceProvisioner) collectScripts(c *terraform.ResourceConfig) ([]io.
|
|||
// Check if inline
|
||||
_, ok := c.Config["inline"]
|
||||
if ok {
|
||||
script, err := p.generateScript(c)
|
||||
scripts, err := p.generateScripts(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rc := ioutil.NopCloser(bytes.NewReader([]byte(script)))
|
||||
return []io.ReadCloser{rc}, nil
|
||||
|
||||
r := []io.ReadCloser{}
|
||||
for _, script := range scripts {
|
||||
r = append(r, ioutil.NopCloser(bytes.NewReader([]byte(script))))
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Collect scripts
|
||||
|
|
|
@ -3,8 +3,11 @@ package remoteexec
|
|||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"reflect"
|
||||
|
||||
"github.com/hashicorp/terraform/config"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
@ -46,7 +49,9 @@ wget http://foobar
|
|||
exit 0
|
||||
`
|
||||
|
||||
func TestResourceProvider_generateScript(t *testing.T) {
|
||||
var expectedInlineScriptsOut = strings.Split(expectedScriptOut, "\n")
|
||||
|
||||
func TestResourceProvider_generateScripts(t *testing.T) {
|
||||
p := new(ResourceProvisioner)
|
||||
conf := testConfig(t, map[string]interface{}{
|
||||
"inline": []interface{}{
|
||||
|
@ -55,12 +60,12 @@ func TestResourceProvider_generateScript(t *testing.T) {
|
|||
"exit 0",
|
||||
},
|
||||
})
|
||||
out, err := p.generateScript(conf)
|
||||
out, err := p.generateScripts(conf)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if out != expectedScriptOut {
|
||||
if reflect.DeepEqual(out, expectedInlineScriptsOut) {
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
}
|
||||
|
@ -80,18 +85,20 @@ func TestResourceProvider_CollectScripts_inline(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if len(scripts) != 1 {
|
||||
if len(scripts) != 3 {
|
||||
t.Fatalf("bad: %v", scripts)
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
_, err = io.Copy(&out, scripts[0])
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
for i, script := range scripts {
|
||||
var out bytes.Buffer
|
||||
_, err = io.Copy(&out, script)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if out.String() != expectedScriptOut {
|
||||
t.Fatalf("bad: %v", out.String())
|
||||
if out.String() != expectedInlineScriptsOut[i] {
|
||||
t.Fatalf("bad: %v", out.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue