0
votes

In the following YAML script I want to pass the IPs as a List in a terraform variable. The variable was already defined as List in Terraform code. The scope is to run this CLI inside an Azure DevOps pipeline on a Windows Agent. When running the pipeline, it fails with the following message: Meaning that -var='ips=$(ips)' was not passed correctly. I have also tried with -var="ips=$(ips)". The value I am trying to assign is a text of ["123.456.111","123.456.222"] How can I correctly pass a parameter as a List in this case?

The code where the variable ips in Terraform is used I have attached below.

enter image description here

 - task: CmdLine@2
            displayName: Terraform Plan
            inputs:
              script: terraform plan -input=false -out=tfplan -var='ips=$(ips)'
              workingDirectory: infrastructure/terraform/dev
locals {
   }
  ips           = tolist(toset(var.ips))
  feature_flags = {
    provision_vm      = tobool(var.provision_vm)
    provision_webapp  = tobool(var.provision_webapp)
  }
}
1
It actually says the variable ips is not declared in the root module, not that it's passed incorrectly. How does your (root) module look like? More importantly how does your variables.tf in there look like and does it have a correct declaration of ips? Looking at the error message I guess not.yvesonline
I think it has. On a Ubuntu maschine I don't have this issue. This is the declaration: variable "ips" { description = "value" type = list default = [""] } . Any suggestion?Pirvu Georgian
And that variable declaration is in infrastructure/terraform/dev? You set a working directory in the task definition so that'll be treated as the main module. It looks like this is a module for a specific stage/environment. But I'm only guessing and people on SO can't help further without seeing the actual Terraform code in infrastructure/terraform.yvesonline
yes, infrastructure/terraform/dev is the root, and contains the variables.tf with ips declared as mentioned abovePirvu Georgian
have also added where the variable is used in the locals.Pirvu Georgian

1 Answers

2
votes

When running command line tools like Terraform it's important to be aware of which command line interpreters and other layers your command will pass through on the way to the command you are eventually running.

On a Unix system like Linux or Mac OS X your command line will typically be interpreted by a shell like bash or zsh. Unix-style shells follow the convention that the ' character marks sequences of characters to be interpreted totally literally, and so with a command line substring like -var='foo=bar baz' the shell will be the one to handle those ', removing them in the process, causing the final argument sent to the program to be -var=foo=bar baz, which happens to be the syntax that Terraform expects for this argument and so it works.

Unfortunately on Windows the conventions are rather different. Your command lines might be handled by the Windows command interpreter (cmd.exe) or by some other interpreter like PowerShell. Each has its own conventions for processing a command line, which means the same command line can be interpreted differently depending on which interpreter you are using.

For running Terraform I would suggest ensuring that you are using the Windows command interpreter if possible, because its command line processing rules are relatively simple: it doesn't interpret quote marks at all and just passes the full command line arguments into the program as a single string. However, that does mean that on Windows a command line like -var='foo=bar baz' will pass to Terraform written exactly like that, with the ' quotes still present, and thus command line parsing will fail.

Terraform on Windows follows the typical command line parsing conventions used by software written in C or using the Windows API function that parses command lines, and part of those conventions is the use of " to indicate sequences of characters where spaces should be taken literally, and so when running Terraform on Windows using the Windows command interpreter you need to enclose literal sequences of characters in " and then escape any literal " characters with a backslash, giving something like this:

-var="ips=[\"123.456.111\",\"123.456.222\"]"

Since you intend to populate this from a variable in your automation tool, this will only work if that automation tool has a mode where it'll automatically escape quote marks with a backslash, otherwise the result won't be valid.

Dealing with all of the different layers of parsing on a templated command line like this can be pretty messy, so it's often easier to instead place the variable values in a .tfvars file and then pass the filename on the command line. In that case Terraform will parse the contents of that file directly, without any interference from command line interpreters, and so you only need to deal with Terraform's own language and not the extra layered shell languages on top.