Skip to content

Commit 5010019

Browse files
authored
action: Add new local_command action to invoke a local executable with provided input (#450)
* initial implementation * update the config directory to work running manually * add count * add test * add tests * don't encode null arguments * add copyright headers * add documentation and example * remove the tests temporarily for the CI * lint * use rc1 for generating docs * add changelog and fix tests for windows * add vscode gitignore * refactor * update docs * replace unreleased plugin testing code w/ TODOs and normal `Check` funcs
1 parent 5dc47e9 commit 5010019

File tree

20 files changed

+885
-49
lines changed

20 files changed

+885
-49
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: FEATURES
2+
body: 'action/local_command: New action that invokes an executable on the local machine.'
3+
time: 2025-11-03T15:39:52.741799-05:00
4+
custom:
5+
Issue: "450"

.github/workflows/test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ jobs:
3737
- name: Set up Terraform
3838
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
3939
with:
40+
# TODO: Remove once Terraform 1.14 GA is released
41+
terraform_version: 1.14.0-rc2
4042
terraform_wrapper: false
4143

4244
- name: Generate

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ website/vendor
2929
# Test exclusions
3030
!command/test-fixtures/**/*.tfstate
3131
!command/test-fixtures/**/.terraform/
32+
33+
.vscode

docs/actions/command.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
page_title: "local_command Action - terraform-provider-local"
2+
subcategory: ""
3+
description: |-
4+
Invokes an executable on the local machine. All environment variables visible to the Terraform process are passed through to the child process. After the child process successfully executes, the stdout will be returned for Terraform to display to the user.
5+
Any non-zero exit code will be treated as an error and will return a diagnostic to Terraform containing the stderr message if available.
6+
---
7+
8+
# local_command (Action)
9+
10+
Invokes an executable on the local machine. All environment variables visible to the Terraform process are passed through to the child process. After the child process successfully executes, the `stdout` will be returned for Terraform to display to the user.
11+
12+
Any non-zero exit code will be treated as an error and will return a diagnostic to Terraform containing the `stderr` message if available.
13+
14+
## Example Usage
15+
16+
For the following bash script (`example_script.sh`):
17+
```bash
18+
#!/bin/bash
19+
20+
DATA=$(</dev/stdin)
21+
echo "stdin: $DATA, args: $@"
22+
```
23+
24+
Here is an example configuration that will run the script after a resource is created:
25+
26+
```terraform
27+
resource "terraform_data" "test" {
28+
lifecycle {
29+
action_trigger {
30+
events = [after_create]
31+
actions = [action.local_command.bash_example]
32+
}
33+
}
34+
}
35+
36+
action "local_command" "bash_example" {
37+
config {
38+
command = "bash"
39+
arguments = ["example_script.sh", "arg1", "arg2"]
40+
stdin = jsonencode({
41+
"key1" : "value1"
42+
"key2" : "value2"
43+
})
44+
}
45+
}
46+
```
47+
48+
The `stdout` will be displayed when the action is invoked:
49+
```bash
50+
$ terraform apply -auto-approve
51+
52+
# .. Terraform CLI output truncated for example purposes
53+
54+
Plan: 1 to add, 0 to change, 0 to destroy. Actions: 1 to invoke.
55+
terraform_data.test: Creating...
56+
terraform_data.test: Creation complete after 0s [id=4b41b541-5550-590a-9949-657e91baa346]
57+
Action started: action.local_command.bash_example (triggered by terraform_data.test)
58+
Action action.local_command.bash_example (triggered by terraform_data.test):
59+
60+
stdin: {"key1":"value1","key2":"value2"}, args: arg1 arg2
61+
62+
63+
Action complete: action.local_command.bash_example (triggered by terraform_data.test)
64+
65+
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
66+
```
67+
68+
<!-- action schema generated by tfplugindocs -->
69+
## Schema
70+
71+
### Required
72+
73+
- `command` (String) Executable name to be discovered on the PATH or absolute path to executable.
74+
75+
### Optional
76+
77+
- `arguments` (List of String) Arguments to be passed to the given command. Any `null` arguments will be removed from the list.
78+
- `stdin` (String) Data to be passed to the given command's standard input.
79+
- `working_directory` (String) The directory path where the command should be executed, either an absolute path or relative to the Terraform working directory. If not provided, defaults to the Terraform working directory.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
resource "terraform_data" "test" {
2+
lifecycle {
3+
action_trigger {
4+
events = [after_create]
5+
actions = [action.local_command.bash_example]
6+
}
7+
}
8+
}
9+
10+
action "local_command" "bash_example" {
11+
config {
12+
command = "bash"
13+
arguments = ["example_script.sh", "arg1", "arg2"]
14+
stdin = jsonencode({
15+
"key1" : "value1"
16+
"key2" : "value2"
17+
})
18+
}
19+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/bash
2+
3+
DATA=$(</dev/stdin)
4+
echo "stdin: $DATA, args: $@"

go.mod

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ go 1.24.0
44

55
require (
66
github.com/google/go-cmp v0.7.0
7+
github.com/hashicorp/go-version v1.7.0
78
github.com/hashicorp/terraform-plugin-framework v1.16.1
89
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0
910
github.com/hashicorp/terraform-plugin-go v0.29.0
11+
github.com/hashicorp/terraform-plugin-log v0.9.0
1012
github.com/hashicorp/terraform-plugin-testing v1.13.3
1113
)
1214

@@ -26,37 +28,35 @@ require (
2628
github.com/hashicorp/go-plugin v1.7.0 // indirect
2729
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
2830
github.com/hashicorp/go-uuid v1.0.3 // indirect
29-
github.com/hashicorp/go-version v1.7.0 // indirect
3031
github.com/hashicorp/hc-install v0.9.2 // indirect
31-
github.com/hashicorp/hcl/v2 v2.23.0 // indirect
32+
github.com/hashicorp/hcl/v2 v2.24.0 // indirect
3233
github.com/hashicorp/logutils v1.0.0 // indirect
33-
github.com/hashicorp/terraform-exec v0.23.0 // indirect
34-
github.com/hashicorp/terraform-json v0.25.0 // indirect
35-
github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect
36-
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 // indirect
34+
github.com/hashicorp/terraform-exec v0.24.0 // indirect
35+
github.com/hashicorp/terraform-json v0.27.2 // indirect
36+
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 // indirect
3737
github.com/hashicorp/terraform-registry-address v0.4.0 // indirect
3838
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
3939
github.com/hashicorp/yamux v0.1.2 // indirect
40-
github.com/kr/pretty v0.3.0 // indirect
40+
github.com/kr/text v0.2.0 // indirect
4141
github.com/mattn/go-colorable v0.1.13 // indirect
4242
github.com/mattn/go-isatty v0.0.20 // indirect
4343
github.com/mitchellh/copystructure v1.2.0 // indirect
4444
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
45-
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
45+
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
4646
github.com/mitchellh/mapstructure v1.5.0 // indirect
4747
github.com/mitchellh/reflectwalk v1.0.2 // indirect
4848
github.com/oklog/run v1.1.0 // indirect
4949
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
5050
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
5151
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
52-
github.com/zclconf/go-cty v1.16.3 // indirect
53-
golang.org/x/crypto v0.41.0 // indirect
54-
golang.org/x/mod v0.26.0 // indirect
55-
golang.org/x/net v0.43.0 // indirect
56-
golang.org/x/sync v0.16.0 // indirect
57-
golang.org/x/sys v0.35.0 // indirect
58-
golang.org/x/text v0.28.0 // indirect
59-
golang.org/x/tools v0.35.0 // indirect
52+
github.com/zclconf/go-cty v1.17.0 // indirect
53+
golang.org/x/crypto v0.43.0 // indirect
54+
golang.org/x/mod v0.28.0 // indirect
55+
golang.org/x/net v0.45.0 // indirect
56+
golang.org/x/sync v0.17.0 // indirect
57+
golang.org/x/sys v0.37.0 // indirect
58+
golang.org/x/text v0.30.0 // indirect
59+
golang.org/x/tools v0.37.0 // indirect
6060
google.golang.org/appengine v1.6.8 // indirect
6161
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
6262
google.golang.org/grpc v1.75.1 // indirect

0 commit comments

Comments
 (0)