terraform-aws-modules / terraform-aws-alb

Terraform module to create AWS Application/Network Load Balancer (ALB/NLB) resources 🇺🇦
https://registry.terraform.io/modules/terraform-aws-modules/alb/aws
Apache License 2.0
427 stars 665 forks source link

Changing to weighted-forward listener rule (to add stickiness) results in error determining target group arn #375

Closed barnabyibis closed 1 week ago

barnabyibis commented 2 weeks ago

Description

I have been using the module with success for a while now. A change in our target solution now requires sticky sessions to some target groups. When I attempt to modify from action.type == "forward" to action.type == "weighted-forward" returns an error

Error: Error in function call │ │ on ....\modules\alb\main.tf line 346, in resource "aws_lb_listener_rule" "this": │ 346: arn = try(target_group.value.arn, aws_lb_target_group.this[target_group.value.target_group_key].arn) │ ├──────────────── │ │ aws_lb_target_group.this is object with 2 attributes │ │ target_group.value is "ecs-ctnr-nz-ecomm-nz-devtest" │ │ Call to function "try" failed: no expression succeeded: │ - Unsupported attribute (at ....\modules\alb\main.tf:346,44-48) │ Can't access attributes on a primitive-typed value (string). │ - Unsupported attribute (at ....\modules\alb\main.tf:346,93-110) │ Can't access attributes on a primitive-typed value (string). │ │ At least one expression must produce a successful result.

Even though I have an aws_lb_target_group that should match, the 'try' declaration fails

terraform state show module.eos_ecs-alb.module.alb.aws_lb_target_group.this[\"ecs-ctnr-nz-ecomm-nz-devtest\"]
# module.eos_ecs-alb.module.alb.aws_lb_target_group.this["ecs-ctnr-nz-ecomm-nz-devtest"]:
resource "aws_lb_target_group" "this" {
    arn                                = "arn:aws:elasticloadbalancing:ap-southeast-2...

Versions

Reproduction Code [Required]

listeners = merge(
    {for container_name, urls in var.container_URLs : 
                  container_name => {
                    ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
                    certificate_arn = var.cert_arn
                    additional_certificate_arns = [for domain, arn in var.customer_certs : arn if contains(concat(urls, local.wildcard_URLs), domain)]
                    # If there are no URLs, I'm expecting the default rule to kick in. This may need to be revisited...
                    rules = [for url in urls : {
                      # priority = 100 <- unsure how to provide an incrementing value for these (not sure it is important, module creates nulls if missing)
                      actions = [{
                        type = "weighted-forward"
                        target_groups = {
                            target_group_key = container_name # Associates by name to matching target_groups resource (created next, below)
                        }
                        stickiness = {
                            enabled = strcontains(container_name, "-ecomm-") ? true : false
                            duration = 600
                        }
                      }]
                      conditions = [{
                        host_header = {
                          values = [url]
                        }
                      }]
                    }]
                    fixed_response = { #default_action
                      content_type = "text/plain"
                      message_body = "Invalid URL - please contact Ibis support"
                      status_code  = "403"
                    }
                  }
                },
                {
                    HTTP_redirect = {
                        port     = 80
                        protocol = "HTTP"
                        redirect = {
                          port        = "443"
                          protocol    = "HTTPS"
                          status_code = "HTTP_301"
                        }
                    }
                }
             )

Steps to reproduce the behavior:

No workspaces

Cache not cleared - I'm relying on the stored state to validate the requested ALB change

Created a standard ALB with simple target groups using the following successful code, then tried to introduce sticky sessions to the listener

listeners = merge(
    {for container_name, urls in var.container_URLs : 
                  container_name => {
                    ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
                    certificate_arn = var.cert_arn
                    additional_certificate_arns = [for domain, arn in var.customer_certs : arn if contains(concat(urls, local.wildcard_URLs), domain)]
                    # If there are no URLs, I'm expecting the default rule to kick in. This may need to be revisited...
                    rules = [for url in urls : {
                      # priority = 100 <- unsure how to provide an incrementing value for these (not sure it is important, module creates nulls if missing)
                      actions = [{
                        type = "forward"
                        target_group_key = container_name # Associates by name to matching target_groups resource (created next, below)
                      }]
                      conditions = [{
                        host_header = {
                          values = [url]
                        }
                      }]
                    }]
                    fixed_response = { #default_action
                      content_type = "text/plain"
                      message_body = "Invalid URL - please contact Ibis support"
                      status_code  = "403"
                    }
                  }
                },
                {
                    HTTP_redirect = {
                        port     = 80
                        protocol = "HTTP"
                        redirect = {
                          port        = "443"
                          protocol    = "HTTPS"
                          status_code = "HTTP_301"
                        }
                    }
                }
             )

Expected behavior

ALB changes by changing some target groups to use sticky sessions

Actual behavior

Error as described prevents apply

Terminal Output Screenshot(s)

Additional context

barnabyibis commented 2 weeks ago

The crux of the issue is that I don't understand the result in the error report

target_group.value is "ecs-ctnr-nz-ecomm-nz-devtest"

when the code says

type = "weighted-forward"
    target_groups = {
        target_group_key = container_name

In other words, I expect target_group.value to be a map(string), not just a string

barnabyibis commented 1 week ago

I found the issue by review a sample: The target groups can be multiple so are expected to be provided as a List. This works:

                      actions = [{
                        type = "weighted-forward"
                        target_groups = [
                            {
                                target_group_key = container_name # Associates by name to matching target_groups resource (created next, below)
                            }
                        ]
                        stickiness = {
                            enabled = strcontains(container_name, "-ecomm-") ? true : false
                            duration = 600
                        }
                      }]

(There is only one 'stickiness' declaration, and it is cast to a list in the module, now I look more closely)