Reputation: 41
I create three modules in Terraform one for EC2, VPC, and security groups. I run full stack for the three modules and I use the output of security groups and the VPC module in the EC2 module but I get that error:
creating EC2 Instance: InvalidSubnetID.NotFound: The subnet ID 'module.vpc_main.primary_private_subnets_id.value[0]' does not exist
status code: 400, request id: d94befb9-a846-47f9-a7c2-c588996a723c
on .terraform/modules/main_ec2/main.tf line 66, in resource "aws_instance" "create_instance":
66: resource "aws_instance" "create_instance" {
the output of the VPC module:
output "primary_public_subnets_id" {
description = "public subnet ID"
value = aws_subnet.primary_public_subnets[*].id
}
output "primary_private_subnets_id" {
description = "public subnet ID"
value = aws_subnet.primary_private_subnets[*].id
}
the output in the state file
outputs": {
"primary_private_subnets_id": {
"value": [
"subnet-098d3aab6a102656c",
"subnet-073699d0e266072d6",
"subnet-07755f92e02ca8756",
"subnet-0a2f21a6e9b80d91e"
],
"type": [
"tuple",
[
"string",
"string",
"string",
"string"
]
]
},
"primary_public_subnets_id": {
"value": [
"subnet-0aea672a2f19cee51",
"subnet-0a014df85bc56acd3"
],
"type": [
"tuple",
[
"string",
"string"
]
]
},
the variables
variable "subnet_id" {
type = list(string)
default = [ "module.vpc_main.primary_public_subnets_id[0]", "module.vpc_main.primary_private_subnets_id[1]" ]
}
the part of EC2 module:
resource "aws_instance" "create_instance" {
ami = "${element(data.aws_ami.ami_id.*.id, count.index)}"
instance_type = var.EC2_Type[count.index]
subnet_id = var.subnet_id[count.index]
associate_public_ip_address = var.associate_public_ip_address[count.index]
vpc_security_group_ids = [ var.vpc_security_group_ids[count.index] ]
key_name = "${local.name}-KP-${var.Server_Name[count.index]}"
iam_instance_profile = aws_iam_instance_profile.iam_profile.name
private_ip = var.EC2_IP[count.index]
count = length(var.ami_name)
}
the EC2 calling module :
module "main_ec2" {
source = "/home/reham/Data/projectes/terraform/modules/EC2Module"
EC2_Type = var.EC2_Type
EC2_IP = var.EC2_IP
subnet_id = var.subnet_id
associate_public_ip_address = var.associate_public_ip_address
vpc_security_group_ids = var.vpc_security_group_ids
}
please note any of the modules work separately in a good way. please how do I get any value from the tuple in the output of the module in Terraform?
Upvotes: 0
Views: 915
Reputation: 18148
If we consider the VPC module is being called as well, you don't have to add the default values to the variable subnet_id
. Instead, you can leave the variable definition without any values:
variable "subnet_id" {
type = list(string)
}
Take a note here that you are using a variable of type list(string)
while the argument for the EC2 instance expects only one value, so it is of type string
. Furthermore, in the EC2 module, you are setting the count
meta-argument to depend on the length of variable ami_name
. So even if you were to make correct value assignments I think you would get a lot of unexpected results. Prior to making any calls to the EC2 module, I suggest fixing this to look more like:
resource "aws_instance" "create_instance" {
count = length(var.subnet_id)
ami = element(data.aws_ami.ami_id.*.id, count.index)
instance_type = var.EC2_Type[count.index]
subnet_id = var.subnet_id[count.index]
associate_public_ip_address = var.associate_public_ip_address[count.index]
vpc_security_group_ids = [var.vpc_security_group_ids[count.index]]
key_name = "${local.name}-KP-${var.Server_Name[count.index]}"
iam_instance_profile = aws_iam_instance_profile.iam_profile.name
private_ip = var.EC2_IP[count.index]
}
It is also a good practice to move the meta-arguments to the top of the resource
block because it's more visible to the reader. I have set the count
to use the length of the subnet_id
variable as I am guessing you want an EC2 instance in each of the subnets.
Another thing that is unclear is if you want to have EC2 instances in private subnets, public subnets, or both. For the sake of simplicity, let's say you want them in the public subnet (since you have the associate_public_ip_address
argument defined). Here you made another mistake, which is trying to set a bool
argument (which can have only true
or false
value) to use a variable with count.index
(var.associate_public_ip_address[count.index]
). That will not work unless variable associate_public_ip_address
is a list of boolean values. If so, that code can stay as such. Last, but not the least, since the VPC module is providing outputs you want, the way to use those outputs is as follows:
module "vpc" {
... your module call goes here ...
}
module "main_ec2" {
source = "/home/reham/Data/projectes/terraform/modules/EC2Module"
EC2_Type = var.EC2_Type
EC2_IP = var.EC2_IP
subnet_id = module.vpc.primary_public_subnets_id
associate_public_ip_address = var.associate_public_ip_address
vpc_security_group_ids = var.vpc_security_group_ids
}
If there are other outputs provided by the VPC module (e.g., the Security Group IDs), you would call it the same as for the subnet IDs:
module.vpc.<name of the output>
Even with the details from my answer there is no guarantee it will work. A lot of refactoring is required for the code to work. Additionally, I strongly suggest understanding types [1] of values arguments in a resource expect (string
, list(string)
, bool
, etc.). You also need to make sure you understand how to reference module outputs [2].
[1] https://www.terraform.io/language/expressions/types
[2] https://www.terraform.io/language/expressions/references#child-module-outputs
Upvotes: 1