Reputation: 10366
With three different environments, I want to be able to dynamically set variables based on the environment. In my example below, let's say the instance type is different between dev and prod. I'm not able to reference instance_type
within the module UNLESS I have a vars.tf
file alongside my terraform.tfvars
.
The error I get is:
unknown variable referenced: 'instance_type'. define it with 'variable' blocks
If that's the case, then wouldn't this file be the same exact file under modules/apollo/vars.tf
?
I thought modules/apollo/vars.tf
defines the necessary variables needed for the module. I didn't think it was necessary within the "root" level under env-dev/services/apollo/
. If there's a "better" way of doing this, I'm all ears.
├── env-dev
│ └── services
│ └── apollo
│ ├── main.tf
│ ├── terraform.tfvars
│ └── vars.tf # Do i need this?
├── env-test
├── global
├── mgmt
└── modules
├── apollo
│ ├── main.tf
│ ├── user_data.tpl
│ └── vars.tf
└── defaults
└── main.tf
instance_type = "t2.medium"
instance_type = "t2.large"
variable "instance_type" {
description = "EC2 Instance Type"
}
resource "aws_instance" "instance" {
...
instance_type = "${var.instance_type}"
...
}
Upvotes: 14
Views: 28716
Reputation: 1306
I've been trying to achieve something similar as intuitively it seems this is how it should work, however I am coming to the conclusion that modules are simply not designed for this use case. Basically you are assigning values to variables that do not exist in your test/prod, to work around this instead of providing assignments in .tfvars you could try to declare them with default values: env-dev/services/apollo/variables.tf
variable "instance_type" {
default = "t2.medium"
}
env-prod/services/apollo/variables.tf
variable "instance_type" {
default = "t2.large"
}
having those declared and assigned with default values still does not automatically link them to the input variables declared in your module, so
additionally in env-dev/services/apollo/main.tf
and env-prod/services/apollo/main.tf
you would still need to fill in properties for your module:
module "aws_inst" {
source = "..\\..\\..\\modules\\apollo"
instance_type = "${var.instance_type}"
}
You can quickly see how this defeats the purpose of modules in this scenario.
To elaborate, I think that modules were not designed for defining single resource per module to be able to fill in it's values dynamically, but rather to create "collections" of resources within a module where they can share/reuse same variables.
Note that when you are assigning value to instance_type
key in module call, you are actually passing that value to modules input variable which is is then assigned to resource key by the same name.
Upvotes: 3
Reputation: 45243
Adjust the structure, this is my understand for your applications.
├── dev
│ └── apollo_terraform.tfvars
├── test
│ └── apollo_terraform.tfvars
├── global
│ └── apollo_terraform.tfvars
├── mgmt
│ └── apollo_terraform.tfvars
├── main.tf, vars.tf, output.tf, apollo.tf, default.tf, etc
└── modules
├── apollo
│ ├── main.tf
│ ├── user_data.tpl
│ └── vars.tf
└── defaults
└── main.tf
apollo.tf
will have source module code to use the share module apollo
. Same setting for default.tf
your plan/apply command should be like this:
terraform plan -var-file=${env}/apollo_terraform.tfvars
Upvotes: 3