listeners must have the same map
alisson276 opened this issue · 3 comments
Description
It's not possible to use different listeners action directives, because the map must match. What can I do to bypass that situation?
The only apprach I can think is to replace this:
for_each = try([each.value.forward], [])
by this:
for_each = try(each.value.forward, null) != null ? [each.value.forward] : []
on all ocurrences (what I actually have done on my fork)
Versions
-
Module version [Required]: 9.1.0
-
Terraform version: v1.6.3
- Provider version(s):
- registry.terraform.io/hashicorp/aws v5.23.1
Reproduction Code [Required]
Steps to reproduce the behavior:
variables.tf
variable "load_balancers" {
type = map(object({
name = optional(string)
create_security_group = optional(bool, false)
enable_deletion_protection = bool
load_balancer_type = string
ip_address_type = string
preserve_host_header = bool
vpc_id = string
subnets = set(string)
security_groups = set(string)
target_groups = optional(map(object({
arn = string
weight = optional(number)
})), {})
listeners = map(object({
port = number
protocol = string
action_type = string
certificate_arn = optional(string)
ssl_policy = optional(string)
redirect = optional(object({
port = number
protocol = string
status_code = string
}))
fixed_response = optional(object({
content_type = string
message_body = string
status_code = number
}))
}))
tags = optional(map(string))
}))
}
prod.tfvars
load_balancers = {
my-alb-prod = {
enable_deletion_protection = true
load_balancer_type = "application"
ip_address_type = "dualstack"
preserve_host_header = true
vpc_id = "<SENSITIVE_INFORMATION>"
subnets = [<SENSITIVE_INFORMATION>]
security_groups = [<SENSITIVE_INFORMATION>]
listeners = {
http = {
port = 80
protocol = "HTTP"
action_type = "redirect"
redirect = {
port = 443
protocol = "HTTPS"
status_code = "HTTP_301"
}
},
https = {
port = 443
protocol = "HTTPS"
certificate_arn = "<SENSITIVE_INFORMATION>"
ssl_policy = "ELBSecurityPolicy-TLS-1-2-Ext-2018-06"
action_type = "fixed-response"
fixed_response = {
content_type = "text/plain"
message_body = ""
status_code = 400
}
}
}
tags = {
Name = "my-alb-prod"
}
}
}
main.tf
module "alb" {
source = "terraform-aws-modules/alb/aws"
for_each = var.load_balancers
name = coalesce(each.value.name, each.key)
create_security_group = each.value.create_security_group
enable_deletion_protection = each.value.enable_deletion_protection
load_balancer_type = each.value.load_balancer_type
ip_address_type = each.value.ip_address_type
preserve_host_header = each.value.preserve_host_header
vpc_id = each.value.vpc_id
subnets = each.value.subnets
security_groups = each.value.security_groups
target_groups = each.value.target_groups
listeners = each.value.listeners
tags = each.value.tags
}
Expected behavior
It should create two listeners, one HTTP, which only redirects to HTTPS, and one HTTPS, which have a default action of returning an empty string.
Actual behavior
I've tried two ways of doing this. First, my listeners
variable was a map(any)
. However, I've received an error when running a plan
The given value is not suitable for var.load_balancers declared at
│ variables.tf:1,1-26: element "hole19-prod": attribute "listeners": all map
│ elements must have the same type.
After this I've created the fixed mapping you can see on variables.tf
, but now the error is:
╷
│ Error: Attempt to get attribute from null value
│
│ on ../../modules/aws-networking-alb/main.tf line 124, in resource "aws_lb_listener" "this":
│ 124: content_type = default_action.value.content_type
│ ├────────────────
│ │ default_action.value is null
│
│ This value is null, so it does not have any attributes.
╵
╷
│ Error: Attempt to get attribute from null value
│
│ on ../../modules/aws-networking-alb/main.tf line 185, in resource "aws_lb_listener" "this":
│ 185: status_code = default_action.value.status_code
│ ├────────────────
│ │ default_action.value is null
│
│ This value is null, so it does not have any attributes.
Terminal Output Screenshot(s)
Additional context
thats because you've defined it this way
listeners = map(object({
port = number
protocol = string
action_type = string
certificate_arn = optional(string)
ssl_policy = optional(string)
redirect = optional(object({
port = number
protocol = string
status_code = string
}))
fixed_response = optional(object({
content_type = string
message_body = string
status_code = number
}))
Don't do that and the problem is resolved - this is why, unfortunately, we typically use any
for complex types
You're right 😅, using any
instead of map(any)
solves the issue.
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.