Motivation
Sometimes you may need to pass extra CLI arguments every time you run certain terraform
commands. For example, you
may want to set the lock-timeout
setting to 20 minutes for all commands that may modify remote state so that
Terraform will keep trying to acquire a lock for up to 20 minutes if someone else already has the lock rather than
immediately exiting with an error.
You can configure Terragrunt to pass specific CLI arguments for specific commands using an extra_arguments
block
in your terraform.tfvars
file:
terragrunt = {
terraform {
# Force Terraform to keep trying to acquire a lock for
# up to 20 minutes if someone else already has the lock
extra_arguments "retry_lock" {
commands = [
"init",
"apply",
"refresh",
"import",
"plan",
"taint",
"untaint"
]
arguments = [
"-lock-timeout=20m"
]
}
}
}
Each extra_arguments
block includes an arbitrary name (in the example above, retry_lock
), a list of commands
to
which the extra arguments should be add, a list of arguments
or required_var_files
or optional_var_files
to add.
With the configuration above, when you run terragrunt apply
, Terragrunt will call Terraform as follows:
When available, it is preferable to use interpolation functions such as get_terraform_commands_that_need_locking and get_terraform_commands_that_need_vars since they provide the complete list of terraform commands that make use of the desired parameter:
terragrunt = {
terraform {
# Force Terraform to keep trying to acquire a lock for up to 20 minutes if someone else already has the lock
extra_arguments "retry_lock" {
commands = ["${get_terraform_commands_that_need_locking()}"]
arguments = ["-lock-timeout=20m"]
}
}
}
> terragrunt apply
terraform apply -lock-timeout=20m
Multiple extra_arguments blocks
You can specify one or more extra_arguments
blocks. The arguments
in each block will be applied any time you call
terragrunt
with one of the commands in the commands
list. If more than one extra_arguments
block matches a
command, the arguments will be added in the order of of appearance in the configuration. For example, in addition to
lock settings, you may also want to pass custom -var-file
arguments to several commands:
terragrunt = {
terraform {
# Force Terraform to keep trying to acquire a lock for
# up to 20 minutes if someone else already has the lock
extra_arguments "retry_lock" {
commands = [
"init",
"apply",
"refresh",
"import",
"plan",
"taint",
"untaint"
]
arguments = [
"-lock-timeout=20m"
]
}
# Pass custom var files to Terraform
extra_arguments "custom_vars" {
commands = [
"apply",
"plan",
"import",
"push",
"refresh"
]
arguments = [
"-var", "foo=bar",
"-var", "region=us-west-1"
]
}
}
}
With the configuration above, when you run terragrunt apply
, Terragrunt will call Terraform as follows:
> terragrunt apply
terraform apply -lock-timeout=20m -var foo=bar -var region=us-west-1
extra_arguments
for init
Extra arguments for the init
command have some additional behavior and constraints.
In addition to being appended to the terraform init
command that is run when you explicitly run terragrunt init
,
extra_arguments
for init
will also be appended to the init
commands that are automatically
run during other commands (see Auto-Init).
You must not specify the -from-module
option (aka. the SOURCE
argument for terraform < 0.10.0) or the DIR
argument
in the extra_arguments
for init
. This option and argument will be provided automatically by terragrunt.
Here’s an example of configuring extra_arguments
for init
in an environment in which terraform plugins are manually installed,
rather than relying on terraform to automatically download them.
terragrunt = {
terraform = {
...
extra_arguments "init_args" {
commands = [
"init"
]
arguments = [
"-get-plugins=false",
"-plugin-dir=/my/terraform/plugin/dir",
]
}
}
}
Required and optional var-files
One common usage of extra_arguments is to include tfvars files. instead of using arguments, it is simpler to use either required_var_files
or optional_var_files
. Both options require only to provide the list of file to include. The only difference is that required_var_files
will add the extra argument -var-file=<your file>
for each file specified and if they don’t exist, terraform will complain. Using
optional_var_files
instead, terragrunt will only add the -var-file=<your file>
for existing files. This allows many conditional
configurations based on environment variables as you can see in the following example:
/my/tf
├── terraform.tfvars
├── prod.tfvars
├── us-west-2.tfvars
├── backend-app
│ ├── main.tf
│ ├── dev.tfvars
│ └── terraform.tfvars
├── frontend-app
│ ├── main.tf
│ ├── us-east-1.tfvars
│ └── terraform.tfvars
terragrunt = {
terraform {
extra_arguments "conditional_vars" {
commands = [
"apply",
"plan",
"import",
"push",
"refresh"
]
required_var_files = [
"${get_parent_tfvars_dir()}/terraform.tfvars"
]
optional_var_files = [
"${get_parent_tfvars_dir()}/${get_env("TF_VAR_env", "dev")}.tfvars",
"${get_parent_tfvars_dir()}/${get_env("TF_VAR_region", "us-east-1")}.tfvars",
"${get_tfvars_dir()}/${get_env("TF_VAR_env", "dev")}.tfvars",
"${get_tfvars_dir()}/${get_env("TF_VAR_region", "us-east-1")}.tfvars"
]
}
}
See the get_tfvars_dir() and get_parent_tfvars_dir() documentation for more details.
Note that terragrunt cannot interpolate terraform variables (${var.xxx}) in the terragrunt configuration, your variables have to be defined through TF_VAR_xxx environment variable to be referred by terragrunt.
With the configuration above, when you run terragrunt apply-all
, Terragrunt will call Terraform as follows:
> terragrunt apply-all
[backend-app] terraform apply -var-file=/my/tf/terraform.tfvars -var-file=/my/tf/backend-app/dev.tfvars
[frontend-app] terraform apply -var-file=/my/tf/terraform.tfvars -var-file=/my/tf/frontend-app/us-east-1.tfvars
> TF_VAR_env=prod terragrunt apply-all
[backend-app] terraform apply -var-file=/my/tf/terraform.tfvars -var-file=/my/tf/prod.tfvars
[frontend-app] terraform apply -var-file=/my/tf/terraform.tfvars -var-file=/my/tf/prod.tfvars -var-file=/my/tf/frontend-app/us-east-1.tfvars
> TF_VAR_env=prod TF_VAR_region=us-west-2 terragrunt apply-all
[backend-app] terraform apply -var-file=/my/tf/terraform.tfvars -var-file=/my/tf/prod.tfvars -var-file=/my/tf/us-west-2.tfvars
[frontend-app] terraform apply -var-file=/my/tf/terraform.tfvars -var-file=/my/tf/prod.tfvars -var-file=/my/tf/us-west-2.tfvars
Handling whitespace
The list of arguments cannot include whitespaces, so if you need to pass command line arguments that include
spaces (e.g. -var bucket=example.bucket.name
), then each of the arguments will need to be a separate item in the
arguments
list:
terragrunt = {
terraform {
extra_arguments "bucket" {
arguments = [
"-var", "bucket=example.bucket.name",
]
commands = [
"apply",
"plan",
"import",
"push",
"refresh"
]
}
}
}
With the configuration above, when you run terragrunt apply
, Terragrunt will call Terraform as follows:
> terragrunt apply
terraform apply -var bucket=example.bucket.name