Terraform - Unable to Run Multiple Commands in Local Exec

Terraform - Unable to run multiple commands in local exec

I think there are two separate things going on here which are actually not related.

The main problem here is in how you've written your local-exec script:

    command = <<EOT
"chmod +x install-istio.sh"
"./install-istio.sh"
EOT

This will become the following shell script to run:

"chmod +x install-istio.sh"
"./install-istio.sh"

By putting the first command line in quotes, you're telling the shell to try to run a program that is called chmod +x install-istio.sh without any arguments. That is, the shell will try to find an executable in your PATH called chmod +x install-istio.sh, rather than trying to run a command called just chmod with some arguments as I think you intended.

Remove the quotes around the command lines to make this work. Quotes aren't needed here because neither of these commands contain any special characters that would require quoting:

    command = <<-EOT
chmod +x install-istio.sh
./install-istio.sh
EOT

The warning message about interpolation-only expressions is unrelated to the problem of running these commands. This is telling you that you've used a legacy syntax that is still supported for backward compatibility but no longer recommended.

If you are using the latest version of Terraform at the time of writing (one of the v0.15 releases, or later) then you may be able to resolve this and other warnings like it by switching into this module directory and running terraform fmt, which is a command that updates your configuration to match the expected style conventions.

Alternatively, you could manually change what that command would update automatically, which is to remove the redundant interpolation markers around path.module:

    working_dir = path.module

Local-exec using powershell not executing commands

I tested the same with something like below :

provider "azurerm" {
features{}
}
data "azurerm_resource_group" "example"{
name = "ansumantest"
}
variable "function_apps" {
default = ["ansumantestfunc1","ansumantestfunc2"]
}
variable "Subscription" {
default = "948d4068-xxxx-xxxx-xxxx-xxxxxxxxxxx"
}
resource "null_resource" "example2" {
count = length(var.function_apps)
provisioner "local-exec" {
command = <<Settings
$ResourceGroupName = "${data.azurerm_resource_group.example.name}"
$FunctionAppName = "${var.function_apps[count.index]}"
$SubscriptionId = "${var.Subscription}"
Get-AzFunctionApp -ResourceGroupName $ResourceGroupName -Name $FunctionAppName -SubscriptionId $SubscriptionId
Settings

interpreter = ["PowerShell", "-Command"]
}
}

Output:

Sample Image

Note :

I am using Terraform v1.1.0 on windows_amd64

  • provider registry.terraform.io/hashicorp/azurerm v2.90.0
  • provider registry.terraform.io/hashicorp/null v3.1.0

Terraform local-exec to pass new resource( not hard-coding)

Use for_each to execute the batch script once per resource in the resource_list variable

resource "null_resource" "mytest" {
for_each = toset(var.resource_list)

# using timestamp() will cause the script to run again for every value on
# every run since the value changes every time.
# you probably don't want that behavior.

# triggers = {
# run = "${timestamp()}"
# }

provisioner "local-exec" {
command = "sh test.sh ${each.value}"
}
}

When you run this the first time it will execute the script once for each of the resources in resource_list. Then the terraform state file will be updated to know what has already run, so any subsequent runs will only include new items added to resource_list.

How to write Windows-compatible command lines in Terraform local-exec provisioner

The procedure and conventions for quoting and escaping on the command line are quite different between Unix and Windows.

On Unix, quoting and escaping is a concern of the shell itself, and Unix shells typically understand the contents of single quotes ' as totally verbatim text, while the contents of " can contain some interpolation metacharacters but spaces are still taken literally, rather than separators. The shell handles the tokenization into a set of arguments and passes those arguments to the program as an array of strings.

On Windows, quoting and escaping is the concern of the program being run1, and not of the command interpreter cmd.exe. The command line you type will (more or less) be passed exactly as you wrote it to the program you're running -- curl in this case -- and it's left entirely up to that program to decide what symbols like " and ' might mean and where to draw the boundaries between separate arguments.

In practice, most modern CLI applications on Windows are either built using Microsoft Visual C++ or with some other software that emulates its command line parsing conventions. If curl is such a program (which is likely, since it is written in C) then unfortunately the relevant rules are quite complicated, but for your purposes here we can reduce it to a few key facts:

  • The single quote character ' is taken literally. Unlike on Unix, it does not represent verbatim text.
  • You can use the double quote character " to represent a sequence where spaces should be taken literally rather than used as argument separators.

Therefore in order to write a command line that is portable across both Unix and Windows, you will need to use the double quote character " and ensure that the strings you interpolate within the quotes don't contain any characters that would be interpreted as special by either set of parsing rules.

In your case, I think that would be the following as long as you can be sure that none of the variables this refers to will contain quote characters, $ characters, or anything else that a Unix shell might interpret as special inside double quotes:

    command =  <<-EOT
curl "https://${var.cognitive_search_name}.search.windows.net/indexes?api-version=2021-04-30-Preview" --header "Accept: application/json" --header "api-key: ${var.key}" --data "@${each.key}"
EOT

Writing portable command lines is quite challenging due to this significant architectural difference between Unix and Windows, which is one of the reasons why the Terraform documentation recommends considering provisioners as a last resort. If possible it would typically be better to use a specialized provider to make a request like this, but I'm not familiar enough with the API you're requesting here to know which provider would potentially offer it.


1 Technically, the command interpreter does do some parsing of its own to handle environment variable substitution like %%FOO%% and the I/O redirection sequences like pipes and >/< markers.

The command interpreter therefore has its own separate escaping syntax which can potentially come into play if your command line ended up including any of the command interpreter's special characters.

Fortunately the command interpreter's parser also has some basic understanding of " as a marker for turning off some of its special processing, but we still need to watch out for %%VARIABLE%% sequences inside quotes, so you'll need to be sure that your variables to substitute don't contain anything like that.



Related Topics



Leave a reply



Submit