Answers: <p>I found a solution - not sure it's the best but it seems to work well enough for my case.</p>
  <p>The solution is in three parts: first I added a variable to provide the default that works for most of my cases:</p>
  <pre><code>variable &quot;default_lb_action&quot; {
    default = {
        &quot;production&quot;: {&quot;type&quot;: &quot;forward&quot;}
        &quot;staging&quot;: {&quot;type&quot;: &quot;forward&quot;}
    }
  }
  </code></pre>
  <p>Then I added a new <code>local</code> like this:</p>
  <pre><code> locals { 
     lb_default_action = {
        type = var.default_lb_action[local.environment].type
        target_group_arn = var.default_lb_action[local.environment].type == &quot;forward&quot; ? lookup(var.default_lb_action[local.environment], &quot;target_group_arn&quot;, aws_alb_target_group.group.arn) : null
        redirect = try(var.default_lb_action[local.environment].redirect, [])
      }
    }
  </code></pre>
  <p>Please note that I've left the option to explicitly declare a target_group_arn, which may or may not be a requirement, and that redirect defaults to an empty list.</p>
  <p>The last step is the load balancer listener definition itself, which now looks like this:</p>
  <pre><code>resource &quot;aws_alb_listener&quot; &quot;listener_https&quot; {
    load_balancer_arn = aws_alb.alb.arn
    port = &quot;443&quot;
    protocol = &quot;HTTPS&quot;
    ssl_policy = &quot;ELBSecurityPolicy-FS-1-2-Res-2019-08&quot;
    certificate_arn = data.aws_acm_certificate.main.arn
    default_action {
        type = local.lb_default_action.type
        target_group_arn = local.lb_default_action.target_group_arn
        dynamic &quot;redirect&quot; {
            for_each = local.lb_default_action.redirect
            iterator = redir
            content {
              host = redir.value[&quot;host&quot;]
              path = redir.value[&quot;path&quot;]
              port = redir.value[&quot;port&quot;]
              protocol = redir.value[&quot;protocol&quot;]
              query = redir.value[&quot;query&quot;]
              status_code = redir.value[&quot;status_code&quot;]
            }
        }
    }
  }
  </code></pre>
  <p>The important bits here are that the <code>target_group_arn</code> can be null (if the <code>type</code> is not <code>&quot;forward&quot;</code>) and that the <code>redirect</code> block may be empty as well.</p>
  <p>With the above, I can set a var like this and get the result I needed:</p>
  <pre><code>default_lb_action = {
    production = {
      type = &quot;redirect&quot;
      redirect = [
        {
          host = &quot;www.example.com&quot;
          path = &quot;/#{path}&quot;
          port = &quot;#{port}&quot;
          protocol = &quot;HTTPS&quot;
          query = &quot;#{query}&quot;
          status_code = &quot;HTTP_301&quot;
        }]
    }
    staging = {&quot;type&quot;: &quot;forward&quot;}
  }
  </code></pre>
  <p>Hope this helps somebody else!</p>
  
Answers: CC BY-SA 4.0
Answers: 2021-08-16T15:40:08.400Z
Answers: 2021-08-16T15:40:08.400Z
Answers: pgcd
Body: <p>I use Terraform a mostly uniform group of servers - EC2, S3 etc. This works reasonably well, except we need to have rather different actions for the load balancers depending on the specific group, and I can't figure out how to do it.</p>
  <p>To be more specific, this is what the common setup looks like</p>
  <pre><code>  resource &quot;aws_alb_listener&quot; &quot;listener_https&quot; {
       load_balancer_arn = aws_alb.alb.arn
       port = &quot;443&quot;
       protocol = &quot;HTTPS&quot;
       ssl_policy = &quot;ELBSecurityPolicy-FS-1-2-Res-2019-08&quot;
       certificate_arn = data.aws_acm_certificate.main.arn
       default_action {
          target_group_arn = aws_alb_target_group.group.arn
          type = &quot;forward&quot;
       }
   }
  </code></pre>
  <p>but in a couple of cases I need the default action to be a redirect, rather than a forward.</p>
  <p>I thought using a <code>dynamic &quot;default_action&quot;</code> block could help, but I can't seem to find a way to set both the name of the fields and the value (which could mean it's not the correct approach, in which case I'd love to know what the correct one is).</p>
  <p>I guess my question could also be generalized to &quot;(how) can I define all the values of a given resource as a single value and then apply them&quot; (equivalent to what I'd do in python by preparing a dict with the values I need and then creating the object with <code>**dict</code>)</p>
  
Tags: <terraform>
Title: Making aws_lb_listener default_action dynamic
UserDisplayName: pgcd
ThreadText: # Making aws_lb_listener default_action dynamic
  
  (Asked by: username_0 on 2021-08-16)
  
  I use Terraform a mostly uniform group of servers - EC2, S3 etc. This works reasonably well, except we need to have rather different actions for the load balancers depending on the specific group, and I can't figure out how to do it.
  
  To be more specific, this is what the common setup looks like
  
  ```
    resource "aws_alb_listener" "listener_https" {
       load_balancer_arn = aws_alb.alb.arn
       port = "443"
       protocol = "HTTPS"
       ssl_policy = "ELBSecurityPolicy-FS-1-2-Res-2019-08"
       certificate_arn = data.aws_acm_certificate.main.arn
       default_action {
          target_group_arn = aws_alb_target_group.group.arn
          type = "forward"
       }
   }
  
  ```
  
  but in a couple of cases I need the default action to be a redirect, rather than a forward.
  
  I thought using a `dynamic "default_action"` block could help, but I can't seem to find a way to set both the name of the fields and the value (which could mean it's not the correct approach, in which case I'd love to know what the correct one is).
  
  I guess my question could also be generalized to "(how) can I define all the values of a given resource as a single value and then apply them" (equivalent to what I'd do in python by preparing a dict with the values I need and then creating the object with `**dict`)
  
  **Tags:** terraform
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_0 on 2021-08-16. Score: 0
  
  I found a solution - not sure it's the best but it seems to work well enough for my case.
  
  The solution is in three parts: first I added a variable to provide the default that works for most of my cases:
  
  ```
  variable "default_lb_action" {
    default = {
        "production": {"type": "forward"}
        "staging": {"type": "forward"}
    }
  }
  
  ```
  
  Then I added a new `local` like this:
  
  ```
   locals { 
     lb_default_action = {
        type = var.default_lb_action[local.environment].type
        target_group_arn = var.default_lb_action[local.environment].type == "forward" ? lookup(var.default_lb_action[local.environment], "target_group_arn", aws_alb_target_group.group.arn) : null
        redirect = try(var.default_lb_action[local.environment].redirect, [])
      }
    }
  
  ```
  
  Please note that I've left the option to explicitly declare a target\_group\_arn, which may or may not be a requirement, and that redirect defaults to an empty list.
  
  The last step is the load balancer listener definition itself, which now looks like this:
  
  ```
  resource "aws_alb_listener" "listener_https" {
    load_balancer_arn = aws_alb.alb.arn
    port = "443"
    protocol = "HTTPS"
    ssl_policy = "ELBSecurityPolicy-FS-1-2-Res-2019-08"
    certificate_arn = data.aws_acm_certificate.main.arn
    default_action {
        type = local.lb_default_action.type
        target_group_arn = local.lb_default_action.target_group_arn
        dynamic "redirect" {
            for_each = local.lb_default_action.redirect
            iterator = redir
            content {
              host = redir.value["host"]
              path = redir.value["path"]
              port = redir.value["port"]
              protocol = redir.value["protocol"]
              query = redir.value["query"]
              status_code = redir.value["status_code"]
            }
        }
    }
  }
  
  ```
  
  The important bits here are that the `target_group_arn` can be null (if the `type` is not `"forward"`) and that the `redirect` block may be empty as well.
  
  With the above, I can set a var like this and get the result I needed:
  
  ```
  default_lb_action = {
    production = {
      type = "redirect"
      redirect = [
        {
          host = "www.example.com"
          path = "/#{path}"
          port = "#{port}"
          protocol = "HTTPS"
          query = "#{query}"
          status_code = "HTTP_301"
        }]
    }
    staging = {"type": "forward"}
  }
  
  ```
  
  Hope this helps somebody else!
  
  
  ---
  
  