Terragrunt: Treat variables defined in leaf terraform.tfvars as the highest precedent variables

Created on 31 Aug 2018  ยท  4Comments  ยท  Source: gruntwork-io/terragrunt

For the following Terragrunt infrastructure code I have

infrastructure/
โ”œโ”€ accounts/      
โ”‚  โ”œโ”€ dev/
โ”‚  โ”‚  โ”œโ”€ environments/              
|  |  |    โ”œโ”€ tst/                   
|  |  |    |  โ”œโ”€ eb_env/  
|  |  |    |  |  โ””โ”€ terraform.tfvars
|  |  |    โ””โ”€ environment.tfvars

The variables defined in terraform.tfvars seem to get overridden from the variables in environment.tfvars which are passed in as optional_var_files. This seems contrary to the idea that the values defined in the lowest leaf node should have precedence.
The variables defined in the lowest terraform.tfvars should have precedence over all values over all the parent var files.

question

Most helpful comment

I was just able to get this working this morning by adding a reference to the working directory terraform.tfvars file in the top level terraform.tfvars file (which I've included below).

Live directory structure

terragrunt-live/
โ”œโ”€ site/
โ”‚  โ””โ”€ site.tfvars          
โ”‚  โ”œโ”€ environment/ 
โ”‚  โ”‚  โ””โ”€ env.tfvars          
โ”‚  โ”‚  โ”œโ”€ app/
โ”‚  โ”‚  โ”‚  โ””โ”€ app.tfvars          
โ”‚  โ”‚  โ”‚  โ”œโ”€ function/    
โ”‚  โ”‚  โ”‚  โ”‚  โ””โ”€ terraform.tfvars          
โ””โ”€ terraform.tfvars
โ””โ”€ account.tfvars

top level terraform.tfvars file

# Terragrunt is a thin wrapper for Terraform that provides extra tools for working with multiple Terraform modules,
# remote state, and locking: https://github.com/gruntwork-io/terragrunt
terragrunt = {
  # Configure Terragrunt to automatically store tfstate files in an S3 bucket
  remote_state {
    backend = "s3"

    config {
      encrypt        = true
      bucket         = "<BUCKETNAME>"
      key            = "${path_relative_to_include()}/terraform.tfstate"
      region         = "us-east-1"
      dynamodb_table = "<TABLENAME>"
      profile        = "terraform_role"
    }
  }

  # Configure root level variables that all resources can inherit
  terraform {
    extra_arguments "bucket" {
      commands = ["${get_terraform_commands_that_need_vars()}"]

      ## The order of these files is reverse order of variable preference. 
      ## (eg. Variables in earlier files will be overriden by variables with the same name in later files)
      optional_var_files = [
        "${get_tfvars_dir()}/${find_in_parent_folders("account.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("site.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("env.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("app.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("domain.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("ntp.tfvars", "ignore")}",
        "${get_tfvars_dir()}/terraform.tfvars",
      ]
    }
  }
}

All 4 comments

This is something built into Terraform itself. Per their docs:

Definition files passed using the -var-file flag will always be evaluated after those in the working directory.

Your terraform.tfvars leaf is just a file "in the working directory." You may be able to make it higher precedency by explicitly passing it using extra_arguments.

I was just able to get this working this morning by adding a reference to the working directory terraform.tfvars file in the top level terraform.tfvars file (which I've included below).

Live directory structure

terragrunt-live/
โ”œโ”€ site/
โ”‚  โ””โ”€ site.tfvars          
โ”‚  โ”œโ”€ environment/ 
โ”‚  โ”‚  โ””โ”€ env.tfvars          
โ”‚  โ”‚  โ”œโ”€ app/
โ”‚  โ”‚  โ”‚  โ””โ”€ app.tfvars          
โ”‚  โ”‚  โ”‚  โ”œโ”€ function/    
โ”‚  โ”‚  โ”‚  โ”‚  โ””โ”€ terraform.tfvars          
โ””โ”€ terraform.tfvars
โ””โ”€ account.tfvars

top level terraform.tfvars file

# Terragrunt is a thin wrapper for Terraform that provides extra tools for working with multiple Terraform modules,
# remote state, and locking: https://github.com/gruntwork-io/terragrunt
terragrunt = {
  # Configure Terragrunt to automatically store tfstate files in an S3 bucket
  remote_state {
    backend = "s3"

    config {
      encrypt        = true
      bucket         = "<BUCKETNAME>"
      key            = "${path_relative_to_include()}/terraform.tfstate"
      region         = "us-east-1"
      dynamodb_table = "<TABLENAME>"
      profile        = "terraform_role"
    }
  }

  # Configure root level variables that all resources can inherit
  terraform {
    extra_arguments "bucket" {
      commands = ["${get_terraform_commands_that_need_vars()}"]

      ## The order of these files is reverse order of variable preference. 
      ## (eg. Variables in earlier files will be overriden by variables with the same name in later files)
      optional_var_files = [
        "${get_tfvars_dir()}/${find_in_parent_folders("account.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("site.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("env.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("app.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("domain.tfvars", "ignore")}",
        "${get_tfvars_dir()}/${find_in_parent_folders("ntp.tfvars", "ignore")}",
        "${get_tfvars_dir()}/terraform.tfvars",
      ]
    }
  }
}

Right, so I suppose the real question is whether this behavior should be by default or not?
To me it just seems natural that the leaf terraform.tfvars values should implicitly have precedence without me explicitly referring to it as a var file argument.

@skang0601 I'd agree that it seems like it should be default. To me it would be logical that if all the files in optional_var_files have overriding functionality and a hierarchical order AND that the working directory terraform.tfvars file is automatically included that it should overwrite the lower ones.

However, I guess that would remove a setup where you didn't want to allow overriding in lower level files. So I suppose a reference to this sort of setup in the documentation would suffice for me.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adborden picture adborden  ยท  4Comments

lsc picture lsc  ยท  4Comments

jeffdyke picture jeffdyke  ยท  3Comments

brikis98 picture brikis98  ยท  4Comments

zachwhaley picture zachwhaley  ยท  3Comments