Have troubles to make if condition with for_each
locals {
services = {
api = {
task_definition = "api.json"
service_discovery_enabled = true
application_loadbalancer = true
}
auth = {
task_definition = "auth.json"
service_discovery_enabled = true
}
post = {
task_definition = "post.json"
service_discovery_enabled = true
application_loadbalancer = true
}
}
}
Try to run resource only for service where application_loadbalancer = true
resource "aws_cloudwatch_dashboard" "this" {
for_each = [for s in var.services : s if lookup(s, "application_loadbalancer", false)]
dashboard_name = "${var.name}-${terraform.workspace}-${each.key}-metrics-dashboard"
dashboard_body = data.template_file.metric_dashboard[each.key].rendered
}
unsuccessfully:
Error: Invalid for_each argument
on ../../../terraform/main.tf line 77, in resource "aws_cloudwatch_dashboard" "this":
1178: for_each = [for s in var.services : s if lookup(s, "application_loadbalancer", false)]
The given "for_each" argument value is unsuitable: the "for_each" argument
must be a map, or set of strings, and you have provided a value of type tuple.
Any ideas on how to resolve it?
1 Like
I’m not sure why the right side of the for_each is treated as a tuple rather than a list of maps. While wrapping it in toset() doesn’t solve the issue, I find the error message illuminating:
The given “for_each” argument value is unsuitable: “for_each” supports maps
and sets of strings, but you have provided a set containing type object.
In particular, “for_each” supports maps and sets of strings. [for s in var.services : s if lookup(s, “application_loadbalancer”, false)] appears to attempt to construct a list/set of maps/objects. If the goal is to pass the entire object, use { for … } to create a map of objects. If only the keys are desired, they can be extracted with keys(). The example below demonstrates both techniques.
locals {
services = {
api = {
task_definition = "api.json"
service_discovery_enabled = true
application_loadbalancer = true
}
auth = {
task_definition = "auth.json"
service_discovery_enabled = true
}
post = {
task_definition = "post.json"
service_discovery_enabled = true
application_loadbalancer = true
}
}
}
provider "null" { }
resource "null_resource" "this" {
# This doesn't work
# for_each = [ for s in local.services : s if lookup(s, "application_loadbalancer", false) ]
# These do
# for_each = toset([ for s in keys(local.services): s if lookup(local.services[s], "application_loadbalancer", false) ])
# for_each = { for s,v in local.services: s => v if lookup(v, "application_loadbalancer", false) }
provisioner "local-exec" {
command = "echo selected: ${each.key}"
}
}
1 Like
Thanks, that helps, but i have another problem with dynamic block that also contains for_each:
resource "aws_ecs_service" "this" {
for_each = local.services
name = each.key
cluster = aws_ecs_cluster.this.name
desired_count = lookup(each.value, "replicas", "1")
launch_type = "FARGATE"
task_definition = "${aws_ecs_task_definition.this[each.key].family}:${max(
aws_ecs_task_definition.this[each.key].revision, data.aws_ecs_task_definition.this[each.key].revision
)}"
deployment_minimum_healthy_percent = 100
deployment_maximum_percent = 200
network_configuration {
security_groups = [
aws_security_group.services[each.key].id,
aws_security_group.services_dynamic[each.key].id
]
subnets = var.vpc_create_nat ? local.vpc_private_subnets_ids : local.vpc_public_subnets_ids
assign_public_ip = ! var.vpc_create_nat
}
dynamic "load_balancer" {
for_each = { for s,v in local.services: s => v if lookup(v, "application_loadbalancer", false) }
content {
target_group_arn = aws_lb_target_group.this[each.key].arn
container_name = local.services[each.key]
container_port = local.services[each.key].container_port
}
}
depends_on = [aws_lb_target_group.this, aws_lb_listener.this, aws_ecs_task_definition.this]
lifecycle {
ignore_changes = [desired_count]
}
}
I got:
Error: Invalid index
on ../../../terraform/tf-aws-fargate/main.tf line 55, in resource "aws_ecs_service" "this":
55: target_group_arn = aws_lb_target_group.this[each.key].arn
|----------------
| aws_lb_target_group.this is object with 1 attribute "api"
| each.key is "auth"
The given key does not identify an element in this collection value.