Two if statements for one argument in a resource

Hello,

I am building out some sns topic subscriptions for three lambda functions. At first, one of these lambda functions had a filter_policy, so I made a conditional. Now, two of these lambda functions need to have a different filter_policy. I am just unable to figure out how to make the logic happen in Terraform.

Here’s the example of my resource with one differing filter policy:

resource "aws_sns_topic_subscription" "subscription" {
  for_each = toset(local.functions)

  topic_arn              = aws_sns_topic.topic.arn
  protocol               = "lambda"
  endpoint               = aws_lambda_function.function[each.value].arn
  endpoint_auto_confirms = true

  filter_policy = each.value == "${var.name}-events-s3-put" ? jsonencode({
    "event" : ["view_sync_status"]
    "status" : ["SUCCESS"]
  }) : null

I need to somehow add this:

filter_policy = each.value == "${var.name}-errors-teams-hook" ? jsonencode({
    "status" = ["FAILURE"]
  }) : null

Hi @wblakecannon,

From what you’ve described here, my first instinct would be to change the for_each expression to be a map of objects where the different filter_policy appears as part of the definition of each element, like this:

locals {
  functions = tomap({
    name-events-s3-put = {
      filter_policy = jsonencode({
        event  = ["view_sync_status"]
        status = ["SUCCESS"]
      })
    }
    name-errors-teams-hook = {
      filter_policy = jsonencode({
        status = ["FAILURE"]
      })
    }
    name-other-example = {
      # You can set filter_policy to null
      # for the functions that don't need
      # it at all.
      filter_policy = null
    }
  })
}

resource "aws_sns_topic_subscription" "subscription" {
  for_each = local.functions

  topic_arn              = aws_sns_topic.topic.arn
  protocol               = "lambda"
  endpoint               = aws_lambda_function.function[each.key].arn
  endpoint_auto_confirms = true

  filter_policy = each.value.filter_policy
}

This example systematically declares all of the subscriptions in the same way based only on differences in the for_each map, and so all of the information about the differences between the functions lives all together in the local.functions value.


However, if it’s important for your situation that the filter policies be separate from the set of function names then you can get a similar effect by making a lookup table of filter policies to refer to:

locals {
  # (your existing definition of "functions" here first)

  function_filter_policies = {
    name-events-s3-put = jsonencode({
      event  = ["view_sync_status"]
      status = ["SUCCESS"]
    })
    name-errors-teams-hook = jsonencode({
      status = ["FAILURE"]
    })
  }
}

resource "aws_sns_topic_subscription" "subscription" {
  # Since we're going to be looking up the
  # filter policies by key anyway, might as
  # well use "chaining" here to say that we're
  # creating one topic subscription per declared
  # function.
  for_each = aws_lambda_function.function

  topic_arn              = aws_sns_topic.topic.arn
  protocol               = "lambda"
  endpoint               = each.value.arn # refers to the current aws_lambda_function.function element
  endpoint_auto_confirms = true

  filter_policy = local.function_filter_policies[each.key]
}

In this second example I used for_each chaining to more concisely describe the relationship between aws_sns_topic_subscription.subscription elements and aws_lambda_function.function elements, which we can do here because aws_lambda_function.function contains the same set of keys as local.functions and also includes the function object attributes, so we can write each.key.arn instead of the longer reference in the previous example.