gruntwork-io / terragrunt

Terragrunt is a flexible orchestration tool that allows Infrastructure as Code written in OpenTofu/Terraform to scale.
https://terragrunt.gruntwork.io/
MIT License
8.01k stars 971 forks source link

using before_hooks to prepare .tfvars files before terraform commands #453

Open ebarault opened 6 years ago

ebarault commented 6 years ago

The doc states:

Before Hooks is a feature of terragrunt that make it possible to define custom actions that will be called before execution of the terraform command.

Right so i tried using them to turn a .tpl.tfvars file into a .tfvars file by injecting vars in it before running the terraform command.

First try: i have the hook preparing the .tfars file right into my terragrunt source dir, the file is created, then the terraform plan command is executed and prompts me for vars that are defined inside the fresh .tfvars file. OK so for some reason the vars are read by terraform from somewhere else.

Second try: i have the hook preparing the .tfars file into terragrunt's tmp dir, the file is created then the terraform plan command is executed and again prompts me for vars that are defined inside the fresh .tfvars file. ??? So again the vars from the fresh .tfvars file are not used by the terraform plan command

Third try: my hook prepares the .tfvars file inside terragrunt' source dir, i run a first time, interrupt after the file is created, run again, et voilà!!! it works... vars are parsed from the .tfvars file. Pretty obvious since it's pretty much as if i was running without the hook.

How should I use terragrunt's hook so that my .tfvars file is created AND used by terraform in the same command?

lorengordon commented 6 years ago

Try having your hook name the file <splat>.auto.tfvars and write it into the tmp directory? .auto indicates to terraform to load the file automatically, without needing to specify it with -var-file... Or setup your terragrunt "extra_arguments" option to pass -var-file <splat>.tfvars to the terraform command...?

ebarault commented 6 years ago

right on spot! i was specifically investigating the fact that the issue comes from

[terragrunt] 2018/03/28 19:53:13 Skipping var-file /path/to/component.tfvars as it does not exist

testing this just now

ebarault commented 6 years ago

confirmed, it works, thank-you @lorengordon 👍 i was not aware of the .auto.tfvars feature

  1. although it's a terraform feature, i think it would be a great addition to terragrunt doc, in the section on optional/required vars
  2. i would expect before hooks to occur before the files are copied to the tmp dir, i find it counter intuitive the way it is right now
lorengordon commented 6 years ago

The .auto thing is documented as a regular Terraform feature, but it is definitely underused and easy to overlook:

For all files which match terraform.tfvars or *.auto.tfvars present in the current directory, Terraform automatically loads them to populate variables.

eak12913 commented 6 years ago

Hey @ebarault, I'll keep working regarding point 2 from your comment

ebarault commented 6 years ago

Hi @eak12913, that's great. You can cc me in the PR if you want a review.

atrakic commented 6 years ago

This *.auto.tfvars does a magic, thx for that. But what about if your hook command needs arguments, can I use existing tfvars file? I would like escape hardcoding arguments : "dev","eu-west-1", "euw1?

 terraform {
   source = "github.com:myorg/modules/foo.git"
    extra_arguments "custom_vars" {
      commands = [
        "apply",    "apply-all",
        "plan",      "plan-all",
        "import",      "destroy", "destroy-all", "validate-all"
      ]
      arguments = [
        "-var-file=${get_tfvars_dir()}/../../../../../account-common.tfvars",
        # This file holds values: region = "eu-west1"  env="dev" tag="euw1": 
        "-var-file=${get_tfvars_dir()}/../../../../region-common.tfvars", 
        "-var-file=terraform.tfvars"
      ]
    }

before_hook "my_hook" {
 commands = ["apply", "plan"]
  execute = [
 "${get_tfvars_dir()}/../..//bin/assume-env", "dev", 
"${get_tfvars_dir()}/local_cmd.sh" , "dev",  "eu-west-1", "euw1" 
 ]
  run_on_error = false
 }
...
}
lorengordon commented 6 years ago

@atrakic a hook works for that also... copy the file to the working/tmp dir after the init command...

    after_hook "tfvars" {
      commands = ["init"]
      execute  = ["cp", "${get_tfvars_dir()}/foo.auto.tfvars", "."]
    }
atrakic commented 6 years ago

@lorengordon Thx, but would it interpolate? Should I use get_env()? It looks it is not allowed: https://github.com/gruntwork-io/terragrunt#interpolation-syntax, or what to use here to escape from harcoding "dev" "eu-west-1" "euw-1"?