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.