Reputation: 1538
I have a module where I am generating several lambdas programmatically using for_each.
resource "aws_lambda_function" "profile" {
for_each = local.lambdas
function_name = each.value.lambda_name
role = var.lambda_assume_role_arn
image_uri = each.value.ecr_repository_uri
package_type = "Image"
vpc_config {
security_group_ids = [var.rds_security_group_id]
subnet_ids = var.subnet_ids
}
}
Two of these generated lambdas I need to to export in output.tf
output "aws_lambda_function_pre_sign_up_arn" {
value = aws_lambda_function.profile[9].arn
}
output "aws_lambda_function_post_confirmation_arn" {
value = aws_lambda_function.profile[0].arn
}
When I apply I get an error:
╷
│ Error: Invalid index
│
│ on ../modules/services/profile/ouptput.tf line 2, in output "aws_lambda_function_pre_sign_up_arn":
│ 2: value = aws_lambda_function.profile[9]
│ ├────────────────
│ │ aws_lambda_function.profile is object with 10 attributes
│
│ The given key does not identify an element in this collection value. An object only supports looking up attributes by name, not by numeric index.
╵
╷
│ Error: Invalid index
│
│ on ../modules/services/profile/ouptput.tf line 7, in output "aws_lambda_function_post_confirmation_arn":
│ 7: value = aws_lambda_function.profile[0]
│ ├────────────────
│ │ aws_lambda_function.profile is object with 10 attributes
│
│ The given key does not identify an element in this collection value. An object only supports looking up attributes by name, not by numeric index.
╵
Here is a snippet of what the locals look like. There are 10 entires in all.
locals {
service = "profile"
lambdas = {
assign_default_group = {
lambda_name = "${lower(var.company)}-${local.service}-${var.environment}-assign_default_group",
ecr_repository_name = "${lower(var.company)}/${local.service}/${var.environment}/lambda/assign_default_group",
ecr_repository_uri = "xxx.dkr.ecr.${var.region}.amazonaws.com/${lower(var.company)}/${local.service}/${var.environment}/lambda/assign_default_group:latest"
lambda_environment_variables = {
RDS_STORAGE_URL = var.storage_url
COGNITO_USER_POOL_ID = jsondecode(data.aws_secretsmanager_secret_version.profile.secret_string)["cognito_user_pool_id"]
}
},
create_account = {
lambda_name = "${lower(var.company)}-${local.service}-${var.environment}-create_account",
ecr_repository_name = "${lower(var.company)}/${local.service}/${var.environment}/lambda/create_account",
ecr_repository_uri = "xxx.dkr.ecr.${var.region}.amazonaws.com/${lower(var.company)}/${local.service}/${var.environment}/lambda/create_account:latest"
lambda_environment_variables = {
RDS_STORAGE_URL = var.storage_url
}
},
...
Upvotes: 1
Views: 2217
Reputation: 18148
As mentioned in the comments, using indexes with resources created with for_each
meta-argument is not possible [1]. If using indexes is required then count
meta-argument should be used [2]. If you decide to proceed with using for_each
, you could fetch the desired outputs in the following way:
output "aws_lambda_function_pre_sign_up_arn" {
value = aws_lambda_function.profile["first_key"].arn
}
output "aws_lambda_function_post_confirmation_arn" {
value = aws_lambda_function.profile["last_key"].arn
}
Since I do not know which key is first (I'm guessing assign_default_group
) and which is the last (for the sake of example, let's go with create_account
), the above becomes:
output "aws_lambda_function_pre_sign_up_arn" {
value = aws_lambda_function.profile["assign_default_group"].arn
}
output "aws_lambda_function_post_confirmation_arn" {
value = aws_lambda_function.profile["create_account"].arn
}
But based on the output name, there is probably a key named post_confirmation
and a key named pre_sign_up
, so you can use that as the key values.
If you need to fetch a certain attribute for a number of Lambda functions (whether it is ARN or something else), you could do the following:
output "lambda_arns" {
value = {
for k, v in aws_lambda_function.profile : k => v.arn
}
}
This will return a map of key/value pairs, where key will again be a key from the local variable lambdas
and the value will be the Lambda function ARN.
Alternatively, you could use the values
built-in function [3] with the splat
expression [4] to derive only values and the return result will be a list (where you could reference elements by index value):
output "lambda_arns" {
value = values(aws_lambda_function.profile)[*].arn
}
There could be more different ways to get the values but it depends on the type of output you would like to get.
[1] https://www.terraform.io/language/meta-arguments/for_each#referring-to-instances
[2] https://www.terraform.io/language/meta-arguments/count#referring-to-instances
[3] https://www.terraform.io/language/functions/values
[4] https://www.terraform.io/language/expressions/splat
Upvotes: 4