provisioner/local-exec: allow user to specify interpreter

This commit is contained in:
Stephen Weatherford 2017-08-22 10:07:32 -07:00 committed by Martin Atkins
parent 1dc3611fbd
commit 5d5f8224d2
3 changed files with 72 additions and 10 deletions

View File

@ -28,6 +28,12 @@ func Provisioner() terraform.ResourceProvisioner {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
}, },
"interpreter": &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
},
}, },
ApplyFunc: applyFn, ApplyFunc: applyFn,
@ -39,19 +45,29 @@ func applyFn(ctx context.Context) error {
o := ctx.Value(schema.ProvOutputKey).(terraform.UIOutput) o := ctx.Value(schema.ProvOutputKey).(terraform.UIOutput)
command := data.Get("command").(string) command := data.Get("command").(string)
if command == "" { if command == "" {
return fmt.Errorf("local-exec provisioner command must be a non-empty string") return fmt.Errorf("local-exec provisioner command must be a non-empty string")
} }
// Execute the command using a shell // Execute the command using a shell
var shell, flag string interpreter := data.Get("interpreter").([]interface{})
if runtime.GOOS == "windows" {
shell = "cmd" var cmdargs []string
flag = "/C" if len(interpreter) > 0 {
} else { for _, i := range interpreter {
shell = "/bin/sh" if arg, ok := i.(string); ok {
flag = "-c" cmdargs = append(cmdargs, arg)
} }
}
} else {
if runtime.GOOS == "windows" {
cmdargs = []string{"cmd", "/C"}
} else {
cmdargs = []string{"/bin/sh", "-c"}
}
}
cmdargs = append(cmdargs, command)
// Setup the reader that will read the output from the command. // Setup the reader that will read the output from the command.
// We use an os.Pipe so that the *os.File can be passed directly to the // We use an os.Pipe so that the *os.File can be passed directly to the
@ -63,7 +79,7 @@ func applyFn(ctx context.Context) error {
} }
// Setup the command // Setup the command
cmd := exec.CommandContext(ctx, shell, flag, command) cmd := exec.CommandContext(ctx, cmdargs[0], cmdargs[1:]...)
cmd.Stderr = pw cmd.Stderr = pw
cmd.Stdout = pw cmd.Stdout = pw
@ -77,9 +93,7 @@ func applyFn(ctx context.Context) error {
go copyOutput(o, tee, copyDoneCh) go copyOutput(o, tee, copyDoneCh)
// Output what we're about to run // Output what we're about to run
o.Output(fmt.Sprintf( o.Output(fmt.Sprintf("Executing: %q", cmdargs))
"Executing: %s %s \"%s\"",
shell, flag, command))
// Start the command // Start the command
err = cmd.Start() err = cmd.Start()

View File

@ -125,3 +125,23 @@ func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfi
return terraform.NewResourceConfig(r) return terraform.NewResourceConfig(r)
} }
func TestResourceProvider_ApplyCustomInterpreter(t *testing.T) {
c := testConfig(t, map[string]interface{}{
"interpreter": []interface{}{"echo", "is"},
"command": "not really an interpreter",
})
output := new(terraform.MockUIOutput)
p := Provisioner()
if err := p.Apply(output, nil, c); err != nil {
t.Fatalf("err: %v", err)
}
got := strings.TrimSpace(output.OutputMessage)
want := "is not really an interpreter"
if got != want {
t.Errorf("wrong output\ngot: %s\nwant: %s", got, want)
}
}

View File

@ -38,3 +38,31 @@ The following arguments are supported:
as a relative path to the current working directory or as an absolute path. as a relative path to the current working directory or as an absolute path.
It is evaluated in a shell, and can use environment variables or Terraform It is evaluated in a shell, and can use environment variables or Terraform
variables. variables.
* `interpreter` - (Optional) If provided, this is a list of interpreter
arguments used to execute the command. The first argument is the
interpreter itself. It can be provided as a relative path to the current
working directory or as an absolute path. The remaining arguments are
appended prior to the command. This allows building command lines of the
form "/bin/bash", "-c", "echo foo". If `interpreter` is unspecified,
sensible defaults will be chosen based on the system OS.
### Interpreter Examples
```hcl
resource "null_resource" "example1" {
provisioner "local-exec" {
command = "open WFH, '>completed.txt' and print WFH scalar localtime"
interpreter = ["perl", "-e"]
}
}
```
```hcl
resource "null_resource" "example2" {
provisioner "local-exec" {
command = "Get-Date > completed.txt"
interpreter = ["PowerShell", "-Command"]
}
}
```