Understanding variable scope with modules

2,823 views
Skip to first unread message

Brian Zambrano

unread,
Aug 5, 2015, 2:46:53 PM8/5/15
to Terraform
I'm trying to understand how variables are used with modules.  Variables from env variables don't seem to be picked up in modules.  Is this true, or am I misunderstanding something?

├── nat
│   ├── nat.tf
│   └── variables.tf
├── stack.tf
└── variables.tf


------------

provider "aws" {
  region     = "${var.region}"
  access_key = "${var.aws_access_key}"
  secret_key = "${var.aws_secret_key}"
}

module "nat" {
    source      = "./nat"
}

-----------------

variable "aws_access_key" {}
variable "aws_secret_key" {}

variable "region" {
  default = "us-west-2"
}


nat/nat.tf
--------------

resource "aws_vpc" "main" {
  cidr_block = "192.168.0.0/16"
  enable_dns_hostnames = true
  tags {
    Name = "${var.environment}Stack"
  }
}

--------------------

variable "environment" {}


I would expect environment to get picked up from an environment variable, if it's set...but it doesn't:

brianz@gold$ TF_VAR_aws_secret_key=foo \
  TF_VAR_aws_access_key=bar \
  TF_VAR_region=abc \
  TF_VAR_environment=bz  \
  terraform plan

There are warnings and/or errors related to your configuration. Please
fix these before continuing.

Errors:

  * 1 error(s) occurred:

* module root: module nat: required variable environment not set


The work around I found was to declare "environment" the nat module section and set it to the variable:

module "nat" {
    source      = "./nat"
    environment = "${var.environment}"
}

But now "environment" is declared in two variables files and references in multiple places....seems pretty clunky.  Why doesn't the module pick up the env variable setting?

BZ

Paul Hinze

unread,
Aug 5, 2015, 5:12:55 PM8/5/15
to terrafo...@googlegroups.com
Hi Brian,

Good question!

Terraform is designed to be very explicit about the flow of data through your configs. Every module (including the top level, which is really just a "root" module) requires an explicit declaration of inputs and outputs. Each module can only access its own inputs, and module callers can only access that module's outputs. Similarly, the outside world is only allowed to interact with root level inputs and outputs.

So in your example, declaring an `environment` input to the "nat" module is precisely the way to do it.

The benefit of this model is that a user approaching any set of Terraform configuration can always know that data follows the same path from explicitly declared inputs to outputs. And a user approaching any module can understand quickly which parts of the module are meant to interact with other components.

This does make for more verbose configs and more lines of "plumbing" required, but we believe that cost is ultimately worth the simpler rules for variable scope and data flow.

I hope this helps to clarify - feel free to follow up if you have any further questions.

Paul


--
This mailing list is governed under the HashiCorp Community Guidelines - https://www.hashicorp.com/community-guidelines.html. Behavior in violation of those guidelines may result in your removal from this mailing list.
 
GitHub Issues: https://github.com/hashicorp/terraform/issues
IRC: #terraform-tool on Freenode
---
You received this message because you are subscribed to the Google Groups "Terraform" group.
To unsubscribe from this group and stop receiving emails from it, send an email to terraform-too...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/terraform-tool/c74c2f1f-bde0-4a7a-817e-bbc31dd3db4b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Brian Zambrano

unread,
Aug 5, 2015, 5:56:38 PM8/5/15
to Terraform
Hi Paul,

Thanks for the explanation...that definitely helps.

I understand the motivation and reasoning behind that design choice.  My initial experience with this is that it's going to be really really verbose and monotonous to maintain variables throughout and across modules.  In a fairly small system this would be maintainable.  However, in any sort of non-trivial stack I can see this becoming tiresome.

I'll keep playing around and see where I end up.  Thanks again for the quick and clear explanation.

For posterity, I also found this issue which explains the behavior succinctly: https://github.com/hashicorp/terraform/issues/697

BZ

Artem Orobets

unread,
Jun 17, 2016, 6:10:22 AM6/17/16
to Terraform
Hi Brian,

I've faced a similar issue as you. I have a configuration with 80 data pipelines that I want to manage with terraform. I created a module to define pipeline. They have only a few input variables are different for them, but a lot of common variables such as database endpoints, subnets etc. So the code became barely readable.

The solution that I found is to move all common configuration to a separate terraform configuration and add terraform_remote_state inside the module to refer to those common configs.

I understand that this solution is not perfect, let me know if you found a better way.

BR,
Artem
Reply all
Reply to author
Forward
0 new messages