i try to generate providers based on location where I am. Here is the folder structure:
src/
├── environments/
│ ├── all/
│ │ └── environment.hcl
│ ├── dev/
│ │ └── environment.hcl
│ ├── test/
│ │ └── environment.hcl
│ └── prod/
│ └── environment.hcl
└── terraform/
└── infra/
├── project1/
│ ├── main.tf
│ ├── variables.tf
│ └── terragrunt.hcl
├── project2/
│ ├── main.tf
│ ├── variables.tf
│ └── terragrunt.hcl
└── terragrunt.hcl
My code in terraform/infra terragrunt file looks like this:
locals {
wrk_path = trimsuffix(path_relative_to_include(), "/")
all_path = "${get_parent_terragrunt_dir()}/../environments/all"
all_config = try(read_terragrunt_config("${local.all_path}/environment.hcl").inputs, {})
env_path = "${get_parent_terragrunt_dir()}/../environments/${local.env}"
env_config = try(read_terragrunt_config("${local.env_path}/environment.hcl").inputs, {})
fin_config = merge(local.all_config, local.env_config)
all_var_file = "${local.all_path}/${local.wrk_path}.tfvars"
env_var_file = "${get_parent_terragrunt_dir()}/../environments/${local.env}/${local.wrk_path}.tfvars"
}
remote_state {
// backend
}
terraform {
// stuff
}
extra_arguments "apply_environment" {
commands = get_terraform_commands_that_need_vars()
optional_var_files = [
local.all_var_file, local.env_var_file
]
}
}
inputs = merge(local.fin_config)
and then, in terraform/infra/project1 i want to reference settings from master terragrunt hcl and i did a code:
include "root" {
path = find_in_parent_folders()
}
generate "provider" {
path = "providers.tf"
if_exists = "overwrite"
contents = <<EOF
provider "azurerm" {
features {}
subscription_id = "abc"
skip_provider_registration = true
alias = "${local.fin_config.law}"
}
provider "azurerm" {
features {}
subscription_id = "${local.fin_config.sub}"
skip_provider_registration = true
}
EOF
}
But it looks like that config from my master terragrunt.hcl is not moved to "local (project1) terragrunt.hcl.
My question is, how to read common inputs in master terragrunt hcl file and use it in project's terragrunt.hcl file? Is it possible? if not, what is the best approach? When i place generate provider block into my master terragrunthcl providers are created in project1 and 2 but i want to have different providers set per project
You want the
local.fin_configfrom your masterterragrunt.hclto be accessible in each project'sterragrunt.hclfile.But, as far as I know, configurations defined in the master file are not automatically available in the child configurations: Terragrunt does not natively support the inheritance of locals across configurations.
However, inputs defined in an included
terragrunt.hclfile can be accessed by the child configuration. That means you can try and use inputs for shared configuration rather than locals.Modify your master
terragrunt.hclinterraform/infrato outputfin_configas an input that can be inherited by child configurations:In your project-specific
terragrunt.hcl(e.g., withinproject1), you should be able to accessfin_configthrough theinputsof the included configuration:For project-specific configurations (e.g., different Azure subscription IDs), you should define these directly within each project's
terragrunt.hclas inputs or manage them through additional.tfvarsfiles specified in theextra_argumentsblock.The error should mean that, when the child configurations try to access
fin_configviainclude.root.inputs.fin_config, thefin_configis not properly initialized or passed down as expected.Terragrunt's
includemechanism allows child configurations to inheritinputsfrom parent configurations, but this inheritance does not extend to thelocalsin the same straightforward way. When you try to passlocalsfrom the parent configuration to the child throughinputs, it is important that theselocalsare fully resolved and available at the time the child configurations are parsed.If
fin_configis dependent on any dynamic values or otherlocalsthat are not resolved in time, it may result in the child configurations receiving anullvalue when they attempt to accessfin_configthroughinclude.root.inputs.fin_config.A workaround for this issue involves making sure that any values you wish to pass down from the master to the child configurations are not dependent on unresolved
locals, or are resolved before they are assigned toinputs.The master
terragrunt.hclwould be (simplified example):The child
terragrunt.hcl:So make sure any
localsused within theinputsblock of the master configuration are statically defined or resolved early enough to be fully available when the child configurations are processed.When accessing map attributes in the
contentsof thegenerateblock, use the["key"]notation to make sure proper interpolation.Double-check the structure and definitions in your configurations to avoid any timing issues with the evaluation of
locals.So you want to dynamically load configurations from
environment.hclfiles, and use these configurations to generate provider configurations across multiple environments. You need to avoid repetition and keep your Terragrunt configuration DRY (Do not Repeat Yourself).The challenge becomes to dynamically include environment-specific settings in the Terragrunt configuration for each project without hardcoding variables or repeating code.
A strategy that might work involves leveraging the
localsblock within each project'sterragrunt.hclto dynamically read environment configurations while still maintaining a level of DRYness by abstracting common logic into a separate file whenever possible.Since direct inheritance of
localsacross Terragrunt configurations is not supported, one approach to minimize repetition involves using theincludeblock alongside a helper function or script.So:
Keep your
environment.hclfiles as they are, centralized under each environment. That will maintain clear, environment-specific configurations.Consider abstracting the logic for reading and processing
environment.hclfiles into a separate script or a Terragruntbefore_hook. That script can be invoked to set environment variables or generate a.tfvarsfile that Terragrunt can read from.A
load-env-config.shscript would be:In each project's
terragrunt.hcl, use a combination ofincludeto inherit global settings andlocalsto dynamically load environment-specific configurations. If necessary, invoke your abstraction to prepare the environment before Terragrunt runs.Dynamically Load Configurations in Project
terragrunt.hcl:You will need a mechanism to determine the current environment (
dev,test,prod, etc.). That could be done through CLI arguments, environment variables, or naming conventions.