If you are creating a VM resource and must run a Bash script as part of the initialization, that can be done within Terraform using the remote-exec provisioner and its ability to execute scripts via ssh.
If you need to send arguments to this script, there is a standard pattern described in the official documentation for first getting the script to the remote system with a file provisioner, then calling remote-exec with inline commands where you can specify arguments.
Arguments can be added to the inline commands by pulling from any local, var, or data as shown below.
locals { params = [ "a", "b", "c"] params_for_inline_command = join(" ",params) } resource "vsphere_virtual_machine" "vm" { # ... # ssh connection values, typically pulled from var connection { type = "ssh" agent = "false" host = "myhost" user = var.user password = var.password } # copies file from local directory to remote directory provisioner "file" { source = "script.sh" destination = "/tmp/script.sh" } # executes the following commands remotely provisioner "remote-exec" { inline = [ "chmod +x /tmp/script.sh", "/tmp/script.sh ${local.params_for_inline_command}", ] } }
Take note that if your ssh connection is made as non-root, sudo may not be password-less. If your script needs a password for sudo, then you’ll need to echo that to the script and use “sudo -S”.
provisioner "remote-exec" { inline = [ "chmod +x /tmp/script.sh", "echo ${var.password} | sudo -S /tmp/script.sh ${local.params_for_inline_command}", ] }
If passing the parameters to the script on the ‘inline’ command becomes to lengthy or complex, you can use another strategy which is to construct the script from a template and have Terraform inject the parameters directly into the script.
Following up on the example above, we can pass the local variables (both array and string) into the Terraform templatefile function.
# make script from template provisioner "file" { destination = "/tmp/script.sh" content = templatefile( "${path.module}/script.sh.tpl", { "params": local.params "params_for_inline_command" : local.params_for_inline_command } ) }
And with a “script.sh.tpl” that looks like below.
#!/bin/bash # will be replaced by Terraform templating default_args="${params_for_inline_command}" # double dollar sign is escape so Terraform does not replace final_args="$${@:-$default_args}" echo "final_args = $final_args" for myarg in $final_args; do echo "arg is $myarg" done echo "Illustrating a way to inject Terraform list variables via templating" %{ for param in params ~} echo "list item param is ${param}" %{ endfor ~}
The resulting file placed unto the remote host will look like:
#!/bin/bash # will be replaced by Terraform templating default_args="a b c" # double dollar sign is escape so Terraform does not replace final_args="${@:-$default_args}" echo "final_args = $final_args" for myarg in $final_args; do echo "arg is $myarg" done echo "Illustrating a way to inject Terraform list variables via templating" echo "list item param is a" echo "list item param is b" echo "list item param is c"
This allows you to insert either default values or unroll sets and arrays of complex variables into the script.
Here is a link to my github templatefile test.
And here is a link to a more advanced scenario where a script is used for data disk initialization of a vsphere vm.
REFERENCES