Terraform: Unable to use tfvars with module definition

Created on 18 Feb 2019  ยท  5Comments  ยท  Source: hashicorp/terraform

Terraform Version

Terraform v0.11.7
+ provider.aws v1.52.0

Project Structure

โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ modules
โ”‚ย ย  โ”œโ”€โ”€ alb
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ main.tf
โ”‚ย ย  โ”‚ย ย  โ””โ”€โ”€ variables.tf
โ”œโ”€โ”€ prod
โ”‚ย ย  โ”œโ”€โ”€ alb
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ consumer_vars.tfvars
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ main.tf
โ”‚ย ย  โ”‚ย ย  โ”œโ”€โ”€ seller_vars.tfvars

Terraform Configuration Files


The 'alb' module in 'main.tf' contains all the required steps to create alb with variables defined in 'variables.tf'. My variables.tf is as below:


terraform {
  backend "consul" {
    address = "consul.prod.com"
    path    = "tf/state/alb"
  }
}
variable "cluster_name" {
  description = "ELB name, e.g cdn"
}
variable "vpc_id" {
    description = "New production VPC id"
}
variable "subnet_ids" {
  description = "Comma separated list of subnet IDs"
}
variable "environment" {
  description = "Environment tag, e.g prod"
}
variable "client_listener_ports" {
    type= "list"
  description = "Client listener ports to be attached to ALB Security Group"
}
variable "log_bucket" {
  description = "S3 bucket name to write ELB logs into"
}
variable "service_name" {
  type = "list"
  description = "List of services that are part of the cluster"
}

I have defined the 'alb' module in prod-> alb-> main.tf as below:


provider "aws" {
  region     = "ap-southeast-1"
}

module "alb" {
   source = "../../modules/alb"
   cluster_name= "${var.cluster_name}"
   service_name= "${var.service_name}"
   subnet_ids= "${var.subnet_ids}"
   environment= "${var.environment}"
   log_bucket="${var.log_bucket}"
   vpc_id="${var.vpc_id}"
   client_listener_ports="${var.client_listener_ports}"
}

Also, I have my cluster specific variables defined in prod-> alb-> consumer_vars.tfvars as below:


    cluster_name= "consumer"
    service_name=["service1","service2","service3"]
    subnet_ids= "subnet-37c,subnet-a10"
    environment= "prod"
    log_bucket="log_bucket"
    vpc_id="vpc-ad"
    client_listener_ports=["9000"]

Expected Behavior

terraform plan -var-file="consumer_vars.tfvars"

The above command should have returned a list of resources that would be created upon 'terraform apply'.

Actual Behavior

Error: module 'alb': unknown variable referenced: 'environment'; define it with a 'variable' block

Error: module 'alb': unknown variable referenced: 'log_bucket'; define it with a 'variable' block

Error: module 'alb': unknown variable referenced: 'vpc_id'; define it with a 'variable' block

Error: module 'alb': unknown variable referenced: 'client_listener_ports'; define it with a 'variable' block

Error: module 'alb': unknown variable referenced: 'cluster_name'; define it with a 'variable' block

Error: module 'alb': unknown variable referenced: 'service_name'; define it with a 'variable' block

Error: module 'alb': unknown variable referenced: 'subnet_ids'; define it with a 'variable' block

Use Case


First off, I am new to Terraform and still exploring the documentations, extensively trying out different configs and observing outputs.

I would want to re-use the module for different cluster specific resource creation without constantly editing 'main.tf' with defined variables.

question

Most helpful comment

I do understand that this can feel redundant! There are a few bits of information that may help you understand why you need to declare variables in your root module (the top-level terraform configuration files) and each individual modules.

The most obvious issue is that you can have multiple modules with the same variable name, but you need to pass a different value to each module.

Imagine a situation where your main.tf references three modules, and each module has a count. Your main.tf therefore might end up with three different variables to pass to the modules' count: module1_count or alb_count, etc.

This might be easier to see in some pseudo-code:

variable "app_count" { }
variable "db_count" { }
variable "alb_count" { }

module "app_servers" {
    count = var.app_count
}

module "db_instances" {
    count = var.db_count
}

module "alb" {
    count = var.alb_count
}

The other thing to know is that terraform loads each module, including the root module, a discrete unit. It needs to parse the root module (your top-level configuration files) before it can start loading the child modules. It cannot get past the first step, loading the root module, if you are using variables that haven't been declared there.

I hope this is helpful information!

All 5 comments

Hi @adithyamenon ,

Frequently, module developers use the same variable name in the top-level configuration and in the modules. That means you need to declare a variable in both your top-level terraform configuration files (in your example, somewhere in prod/alb/, and in the module (again, in your example modules/alb/variables/tf.

I believe if you add the variables from the error messages to a .tf file in the module you'll be all set.

@mildwonkey I have encountered similar issue and your suggestion did work. This is a little counter - intuitive to declare the variable again at the module and resource config files.

Thanks @mildwonkey! This worked for me.

But yes, as @kbaddi mentioned, isn't it redundant to declare variables both at resource and module level? As we mention the 'source' in the resource main.tf, shouldn't terraform be able to load the variables.tf from the module?

I do understand that this can feel redundant! There are a few bits of information that may help you understand why you need to declare variables in your root module (the top-level terraform configuration files) and each individual modules.

The most obvious issue is that you can have multiple modules with the same variable name, but you need to pass a different value to each module.

Imagine a situation where your main.tf references three modules, and each module has a count. Your main.tf therefore might end up with three different variables to pass to the modules' count: module1_count or alb_count, etc.

This might be easier to see in some pseudo-code:

variable "app_count" { }
variable "db_count" { }
variable "alb_count" { }

module "app_servers" {
    count = var.app_count
}

module "db_instances" {
    count = var.db_count
}

module "alb" {
    count = var.alb_count
}

The other thing to know is that terraform loads each module, including the root module, a discrete unit. It needs to parse the root module (your top-level configuration files) before it can start loading the child modules. It cannot get past the first step, loading the root module, if you are using variables that haven't been declared there.

I hope this is helpful information!

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rkulagowski picture rkulagowski  ยท  3Comments

carl-youngblood picture carl-youngblood  ยท  3Comments

franklinwise picture franklinwise  ยท  3Comments

ketzacoatl picture ketzacoatl  ยท  3Comments

rjinski picture rjinski  ยท  3Comments