In this article I will explain two different ways to pass variables values inside terraform modules. Modules let you separate your code into small units and help the engineer structure its project better.
https://www.terraform.io/language/modules/syntax
Modules in terraform (terraform files) can be placed on folders and their location should be provided on the module directive. Lets say for example that you host a main.tf on your current working directory which should call two modules. The first module would be a storage account and the second would be an app service. Your main.tf file should look like below.
module "app_service_test" { source = "./modules/appservice" } module "storage_account_test" { source = "./modules/storageaccount" }
However you want to pass some variables inside the child modules for example the resource group name, location etc.
First method – Define variables on root module
The first way you can pass variables inside your child modules would be to define a variables.tf file on your main module and a terraform.tfvars. Then you should also define a variables.tf file inside each module and contain the definition of each module.
terraform.tfvars (root module)
app_service_plan_name = "ger-plan-test" app_service_name = "ger-site-test" resource_group_name = "geralexgr-terraform-rg" resource_group_location = "West Europe" storage_account_name = "geralexgrsgv2"
variables.tf (root module)
variable "storage_account_name" { type = string description = "Storage account name" default = "" } variable "resource_group_name" { type = string description = "RG name in Azure" } variable "app_service_plan_name" { type = string description = "App Service Plan name in Azure" } variable "app_service_name" { type = string description = "Name for the app service" } variable "resource_group_location" { type = string description = "RG location in Azure" }
variables.tf (storageaccount module)
variable "storage_account_name" { type = string description = "Storage account name" } variable "resource_group_name" { type = string description = "RG name in Azure" } variable "resource_group_location" { type = string description = "RG location in Azure" }
variables.tf (appservice module)
variable "app_service_plan_name" { type = string description = "App Service Plan name in Azure" } variable "app_service_name" { type = string description = "Name for the app service" } variable "resource_group_name" { type = string description = "RG name in Azure" } variable "resource_group_location" { type = string description = "RG location in Azure" }
Then on your main module you should call your child modules as follows:
module "app_service_test" { source = "./modules/appservice" app_service_plan_name = var.app_service_plan_name app_service_name = var.app_service_name resource_group_name = var.resource_group_name resource_group_location = var.resource_group_location } module "storage_account_test" { source = "./modules/storageaccount" storage_account_name = var.storage_account_name resource_group_name = var.resource_group_name resource_group_location = var.resource_group_location }
Second method – Pass variables on module call
With this approach you do not need to have variables.tf file and terraform.tfvars file inside your root module. You only need the definition as described above inside appservice and storageaccount folders (variables.tf).
variables.tf (appservice module)
variable "app_service_plan_name" { type = string description = "App Service Plan name in Azure" } variable "app_service_name" { type = string description = "Name for the app service" } variable "resource_group_name" { type = string description = "RG name in Azure" } variable "resource_group_location" { type = string description = "RG location in Azure" }
variables.tf (storageaccount module)
variable "storage_account_name" { type = string description = "Storage account name" } variable "resource_group_name" { type = string description = "RG name in Azure" } variable "resource_group_location" { type = string description = "RG location in Azure" }
Then your main.tf file should be:
module "app_service_test" { source = "./modules/appservice" app_service_plan_name = "ger-plan-test" app_service_name = "ger-site-test" resource_group_location = "West Europe" resource_group_name = "geralexgr-terraform-rg" } module "storage_account_test" { source = "./modules/storageaccount" storage_account_name = "geralexgrsgv2" resource_group_name = "geralexgr-terraform-rg" resource_group_location = "West Europe" }
In the first method, do we need to define the same variable in the root module (appservice) and also in our code where we are referring to that module?
Indeed Sunil. With the first method you bypass the need of passing variables when calling the module. Inside each module only the definitions of the variables exist and you pass all variables in the root module terraform.tfvars
Thank you very much for your swift response dear friend,
I am in a situation where i am trying to Azure terraform-azurerm-aks module (built and owned by azure), for example, if you take the folder inside this repository, there is something called as ‘examples/with_acr’, where it has the reference to the terraform module, https://github.com/Azure/terraform-azurerm-aks/blob/main/examples/with_acr/main.tf#L58 – I want to pass this value as per my environment (dev, test and prod), i see that this has already been mentioned in the variables.tf inside the module, https://github.com/Azure/terraform-azurerm-aks/blob/main/variables.tf#L492, what i am assuming is as it is already defined inside the module, can’t we pass this through the terraform.tfvars, how do i make this value to be dynamic in my code? Please help me on this.
I have an example for that. I hope this article helps you. https://blog.geralexgr.com/automation/create-multiple-environments-with-terraform-modules-app-service-azure-example . I believe is somehow what you need.
Please stay with me on this, i am going to provide you a example with a branch of your code, I am trying to push those changes, this will give you an idea what i am trying to do.
@geralexgr, could you please look into this pull request that i had created for your repository?
https://github.com/geralexgr/terraform-module-environments-deploy/pull/1
Thank you very much for your swift response dear friend, I am in a situation where i am trying to Azure terraform-azurerm-aks module (built and owned by azure), for example, if you take the folder inside this repository, there is something called as ‘examples/with_acr’, where it has the reference to the terraform module, github.com/Azure/terraform-azurerm-aks/blob/main/examples/with_acr/main.tf#L58 – I want to pass this value as per my environment (dev, test and prod), i see that this has already been mentioned in the variables.tf inside the module, https://github.com/Azure/terraform-azurerm-aks/blob/main/variables.tf#L492, what i am assuming is as it is already defined inside the module, can’t we pass this through the terraform.tfvars, how do i make this value to be dynamic in my code? Please help me on this.
It seems inefficient and not “DRY” (Don’t Repeat Yourself) to have to duplicate the same variables in multiple places. Is this really the best Terraform can do? I saw someone use outputs.tf to define variables and then import those outputted variables as a “globals” type of approach. I’m not loving either method above, but understand it can be done those ways.
indeed, we could not describe the mentioned methods as a DRY methodology but we could say that terraform is not oop and those concepts cannot be replicated 100% percent in iac languages.
[…] Pass variables values inside terraform modules […]