Given this module input:
variable "port_mapping_metadata" {
type = map(object({
target_type = optional(string, "instance")
ssl_policy = optional(string)
listener_cert_arn = optional(string)
additional_SNI_listener_cert_arns = optional(list(string),[])
...
I'm trying to create a resource per port_mapping_metadata
(if not null, keys may be duplicates across resources), per item in additional_SNI_listener_cert_arns
(if not empty). So for the following input:
"bar" = {
vpc_name = "foo"
name = "bar"
type = "application"
port_mapping_metadata = {
"forward" = {
instance_names = ["inst"]
listener_cert_arn = "arn:aws:acm:us-east-1:1234:certificate/abcd"
additional_SNI_listener_cert_arns = ["arn:aws:acm:us-east-1:1234:certificate/defg", "arn:aws:acm:us-east-1:1234:certificate/hijk"]
"bax" = {
vpc_name = "foo"
name = "bax"
type = "application"
port_mapping_metadata = {
"forward" = {
instance_names = ["inst2"]
listener_cert_arn = "arn:aws:acm:us-east-1:1234:certificate/abcd"
additional_SNI_listener_cert_arns = ["arn:aws:acm:us-east-1:1234:certificate/zle"]
(under another key)
"bar" = {
vpc_name = "foo"
name = "bar"
type = "application"
port_mapping_metadata = {
"forward" = {
instance_names = ["inst"]
listener_cert_arn = "arn:aws:acm:us-east-1:1234:certificate/abcd"
I would expect the following for_each result:
{
"bar-0" = "arn:aws:acm:us-east-1:1234:certificate/defg"
"bar-1" = "arn:aws:acm:us-east-1:1234:certificate/hijk"
"bax-0" = "arn:aws:acm:us-east-1:1234:certificate/zle"
}
I have tried writing the resource as with a for_each as follows:
resource "aws_lb_listener_certificate" "additional_SNI_listener_certs" {
for_each = {
for k, v in var.port_mapping_metadata : k => {
for index, cert_arn in try(v.additional_SNI_listener_cert_arns, []) : "${k}-${index}" => cert_arn
}
if try(v.additional_SNI_listener_cert_arns, []) != [] && try(v.additional_SNI_listener_cert_arns, null) != null
}
##this _should_ be "{ "listener_name-0" = "arn1" , ... }"
listener_arn = aws_lb_listener.all[element(split("-", each.key), 0)].arn ##this should be "listener_name"
certificate_arn = each.value ##this should be "arn1"
}
But for some reason I get the error:
│ Error: Incorrect attribute value type
│
│ on .terraform/modules/load_balancer/load_balancer.tf line 235, in resource "aws_lb_listener_certificate" "additional_SNI_listener_certs":
│ 235: certificate_arn = each.value
│ ├────────────────
│ │ each.value is object with no attributes
│
│ Inappropriate value for attribute "certificate_arn": string required.
I can't understand why each.value
in the resource is not a single string arn1
. I'm sure I'm missing something simple, but I can't figure out what it is. Also open to any other way of doing this.
By looking at your code, I think the for_each
is getting the following map as input. However, you must verify it by adding a terraform output to print the result of the expression.
{
bar = {
"bar-0" = "arn:aws:acm:us-east-1:1234:certificate/defg"
"bar-1" = "arn:aws:acm:us-east-1:1234:certificate/hijk"
}
bax = {
"bax-0" = "arn:aws:acm:us-east-1:1234:certificate/zle"
}
}
Now as per your requirement, to get the following map input to the for_each
{
"bar-0" = "arn:aws:acm:us-east-1:1234:certificate/defg"
"bar-1" = "arn:aws:acm:us-east-1:1234:certificate/hijk"
"bax-0" = "arn:aws:acm:us-east-1:1234:certificate/zle"
}
You need to modify the code to the following
locals {
original_for_each_expr = {
for k, v in var.port_mapping_metadata : k => {
for index, cert_arn in try(v.additional_SNI_listener_cert_arns, []) : "${k}-${index}" => cert_arn
}
if try(v.additional_SNI_listener_cert_arns, []) != [] && try(v.additional_SNI_listener_cert_arns, null) != null
}
desired_for_each_expr = zipmap(
flatten(
[ for i in local.original_for_each_expr : keys(i) ]
),
flatten(
[ for i in local.original_for_each_expr : values(i) ]
)
)
}
resource "aws_lb_listener_certificate" "additional_SNI_listener_certs" {
for_each = local.desired_for_each_expr
...
}
Also, as I suggested earlier, add terraform outputs
to see if you are getting the desired value from the expression to pass it to the for_each
.
output "original_for_each_expr" {
value = local.original_for_each_expr
}
output "desired_for_each_expr" {
value = local.desired_for_each_expr
}