Terraform correlation to resource with for_each - amazon-web-services

I'm using below code to assign defualt subnets to ASG
resource "aws_autoscaling_group" "ecs_spot_asg" {
for_each = data.aws_subnet_ids.all_subnets.ids
.... etc...
Subnets done via
data "aws_subnet_ids" "all_subnets" {
vpc_id = data.aws_vpc.default.id
}
Below I have aws_autoscaling_policy and I'm stuck on how to relate one to the other
resource "aws_autoscaling_policy" "ecs_cluster_scale_policy" {
autoscaling_group_name = aws_autoscaling_group.ecs_spot_asg.name
Getting error:
Because aws_autoscaling_group.ecs_spot_asg has "for_each" set, its
attributes must be accessed on specific instances.
For example, to correlate with indices of a referring resource, use:
aws_autoscaling_group.ecs_spot_asg[each.key]
How this should be modified ?

My mistake was adding [] to vpc_zone_identifier = data.aws_subnet_ids.all_subnets.ids
So instead of vpc_zone_identifier = [data.aws_subnet_ids.all_subnets.ids] it should be vpc_zone_identifier = data.aws_subnet_ids.all_subnets.ids

Related

Terraform create multiple tags for subnets

I am trying to create VPC Module, here i am facing issue with private subnets. We have multiple resources like RDS, REDSHIFT, CASSANDRA. I want to create subnet for each of this resource in each AZ from single block of code. How ever i am unable figure out how to assign the tags in that case.
resource "aws_subnet" "packages_subnet" {
count = "${length(var.packages_subnet)}"
vpc_id = "${aws_vpc.vpc.id}"
cidr_block = "${element(var.packages_subnet, count.index)}"
availability_zone = "${element(var.availability_zones, count.index)}"
map_public_ip_on_launch = false
tags = {
Name = "${var.env_name}-${element(var.test, count.index)}-${element(var.availability_zones, count.index)}"
}
}
this is how my vars.tf looks like
variable "test" {
type = list
default = ["rds","redshift","lambda","emr","cassandra","redis"]
}
with the above approach rds subnet is always creating in 1a.
and redshift in 1b.
module "Networking" {
source = "../modules/Networking"
packages_subnet = ["10.3.4.0/24", "10.3.5.0/24", "10.3.6.0/24", "10.3.10.0/24", "10.3.7.0/24", "10.3.8.0/24", "10.3.9.0/24", "10.3.11.0/24", "10.3.12.0/24", "10.3.13.0/24", "10.3.14.0/24", "10.3.15.0/24", "10.3.16.0/24", "10.3.17.0/24", "10.3.18.0/24"]
}

Get first element of a tuple in terraform

I'm trying to deploy my EKS nodes with only one subnet but I dont know how to give to the resource only one. I show you my code:
resource "aws_eks_node_group" "managed_workers" {
for_each = var.nodegroups[terraform.workspace]
cluster_name = aws_eks_cluster.cluster.name
node_group_name = each.value.Name
node_role_arn = aws_iam_role.managed_workers.arn
subnet_ids = aws_subnet.private.*.id
On the other hand I have a normal task to create the subnets and give the ouput to all my code:
resource "aws_subnet" "private" {
count = length(local.subnet_priv)
vpc_id = var.vpc_id[terraform.workspace]
cidr_block = local.subnet_priv[count.index]
availability_zone = element(lookup(var.availability_zones, terraform.workspace), count.index)
map_public_ip_on_launch = false
So.. I don't know how to get from my subnet_ids argument only the first subnet of the tuple. Now, as you can see, I'm getting all of them but I tried different ways to do but with no success (aws_subnet.private[0].*.id , aws_subnet.private[0].id, etc)
Any idea?
Thanks a lot!
EKS node group subnet_ids arguments expects a tuple. In the original example subnet_ids = aws_subnet.private.*.id the splat operator is used. The spear operator (*) essentially creates a tuple with all the available resources, in our case all the available subnets.
If we want to pass only one subnet from all the available ones, we have to create a tuple with a single element. We could do that by taking the first element from all the existing ones, for example:
subnet_ids = [aws_subnet.private[0].id]
Although, this might work, I personally don't really consider it to be elegant solution. Certainly a better way to accomplish the same result is to modify the local.subnet_priv tuple to contain only one subnet id.

Terraform outs from a resource called via a for_each

I'm wondering if anyone can help me with the following I have a base resource to create aws subnets
resource aws_subnet subnet {
vpc_id = var.vpc_id
cidr_block = var.cidr_block
}
output subnetId {
value = aws_subnet.subnet.id
}
module private_subnet {
source = "linktoresourcedetailedabove"
for_each = var.privateSubnet
vpd.id = var.vpc_id
cidr_block = each.value.cidr_block
}
I have a module which calls using a for_each loop based on a var based in, my question is this resource might be called 10 times and I want to store each id and then access this from another module but I seem to be hitting issues here, I tried updating aws_subnet.subnet.id to aws_subnet.subnet.*.id but am still not having anyluck and can't seem to find anything out there that can help me.
If your private_subnet modules has output
output subnetId {
value = aws_subnet.subnet.id
}
then once you create your private_subnet modules, you can get the list of all subnetId creates as:
values(module.private_subnet)[*].subnetId

Terraform: length() on data source cannot be determined until apply?

I am trying to dynamically declare multiple aws_nat_gateway data sources by retrieving the list of public subnets through the aws_subnet_ids data source. However, when I try to set the count parameter to be equal to the length of the subnet IDs, I get an error saying The "count" value depends on resource attributes that cannot be determined until apply....
This is almost in direct contradiction to the example in their documentation!. How do I fix this? Is their documentation wrong?
I am using Terraform v0.12.
data "aws_vpc" "environment_vpc" {
id = var.vpc_id
}
data "aws_subnet_ids" "public_subnet_ids" {
vpc_id = data.aws_vpc.environment_vpc.id
tags = {
Tier = "public"
}
depends_on = [data.aws_vpc.environment_vpc]
}
data "aws_nat_gateway" "nat_gateway" {
count = length(data.aws_subnet_ids.public_subnet_ids.ids) # <= Error
subnet_id = data.aws_subnet_ids.public_subnet_ids.ids.*[count.index]
depends_on = [data.aws_subnet_ids.public_subnet_ids]
}
I expect to be able to apply this template successfully, but I am getting the following error:
Error: Invalid count argument
on ../src/variables.tf line 78, in data "aws_nat_gateway" "nat_gateway":
78: count = "${length(data.aws_subnet_ids.public_subnet_ids.ids)}"
The "count" value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the count depends on.
It seems you are trying to fetch subnets that weren't created yet or they couldn't be determinated, the terraform cmd output suggests you add -target flag to create the VPC and subnets or do another task first, after that, you'll apply the nat_gateway resource. I suggest you use the AZs list instead of subnets ids, I'll add a simple example below.
variable "vpc_azs_list" {
default = [
"us-east-1d",
"us-east-1e"
]
}
resource "aws_nat_gateway" "nat" {
count = var.enable_nat_gateways ? length(var.azs_list) : 0
allocation_id = "xxxxxxxxx"
subnet_id = "xxxxxxxxx"
depends_on = [
aws_internet_gateway.main,
aws_eip.nat_eip,
]
tags = {
"Name" = "nat-gateway-name"
"costCenter" = "xxxxxxxxx"
"owner" = "xxxxxxxxx"
}
}
I hope will be useful to you and other users.

Terrafrom datasource aws_vpcs - count.index error

I am trying to use data source aws_vpcs to get the vpc id having specific tag.
For reference:
https://www.terraform.io/docs/providers/aws/d/vpcs.html
Below is my terraform yaml file.
Terrafrom version used is: 0.12.3
data "aws_vpcs" "foo" {
tags = {
Name = "test1-VPC"
}
}
resource "aws_security_group" "cluster" {
count = "${length(data.aws_vpcs.foo.ids)}"
vpc_id = "${tolist(data.aws_vpcs.foo.ids)[count.index]}"
}
resource "aws_security_group_rule" "cluster-ingress-node-https" {
description = "Rule to do xyz"
from_port = 443
protocol = "tcp"
security_group_id = "${aws_security_group.cluster.id}"
to_port = 443
type = "ingress"
}
I am getting below error. Request for help to fix this
terraform plan
Error: Missing resource instance key
on modules/eks/eks-cluster.tf line 40, in resource "aws_security_group_rule" "cluster-ingress-node-https":
40: security_group_id = "${aws_security_group.cluster.id}"
Because aws_security_group.cluster has "count" set, its attributes must be
accessed on specific instances.
For example, to correlate with indices of a referring resource, use:
aws_security_group.cluster[count.index]
You are creating a list of aws_security_group as you are using count on the aws_security_group resource. The error even mentions it:
Because aws_security_group.cluster has "count" set, its attributes
must be accessed on specific instances.
So either you need to include count on the aws_security_group_rule resource and create one aws_security_group_rule for each aws_security_group created, or in the case you expect only one VPC to be returned, create only one aws_security_group by accessing the returned aws_vpcs.foo.ids with index 0.
You will need to convert the list of security group.
Terraform provides flatten function to do that https://nedinthecloud.com/2018/07/16/terraform-fotd-flatten/
You should not get this error afterwards
I know this was posted a while ago. Stumbled upon this issue.
${aws_security_group.cluster.*.id} should do it.
Since the resource aws_security_group is creating multiple security groups with count, resource block aws_security_group_rule needs to reference the correct index in the list.