Reputation: 308
I need my resources to be created on specified environments. For example, if I have a AWS Lambda that is not ready for production, I need it to only exist in development environment. Is there a nice way to do this? I know that it's possible to set count
to 0, but I'm not sure how to cascade this decision to other resources.
For example, I have a resource for an AWS Lambda and the count
is set to 0.
resource "aws_lambda_function" "example_lambda" {
count ? local.is_production ? 0 : 1
}
How do I cascade this decision to other resources that depends on the AWS Lambda above?
And let's say I have a S3 Bucket which will invoke the Lambda function.
resource "aws_s3_bucket" "example_bucket" {
bucket = "bucket_name"
}
resource "aws_lambda_permission" "example_bucket_etl" {
statement_id = "AllowExecutionFromS3Bucket"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.example_lambda.arn
principal = "s3.amazonaws.com"
source_arn = aws_s3_bucket.example_bucket.arn
}
resource "aws_s3_bucket_notification" "bucket_notification" {
bucket = aws_s3_bucket.example_bucket.id
lambda_function {
lambda_function_arn = aws_lambda_function.example_lambda.arn
events = ["s3:ObjectCreated:*"]
filter_prefix = "example_bucket/"
filter_suffix = ".txt"
lambda_function {
lambda_function_arn = aws_lambda_function.another_lambda_function.arn
events = ["s3:ObjectCreated:*"]
filter_prefix = "another_example_bucket/"
filter_suffix = ".txt"
}
}
Upvotes: 2
Views: 3844
Reputation: 74084
When you use count
in a resource
block, that makes Terraform treat references to that resource elsewhere as producing a list of objects representing each of the instances of that resource.
Since that value is just a normal list value, you can take its length in order to concisely write down what is essentially the statement "there should be one Y for each X", or in your specific case "there should be one lambda permission for each lambda function".
For example:
resource "aws_lambda_function" "example" {
count = local.is_production ? 0 : 1
# ...
}
resource "aws_lambda_permission" "example_bucket_etl" {
count = length(aws_lambda_function.example)
function_name = aws_lambda_function.example[count.index].name
# ...
}
Inside the aws_lambda_permission
configuration we first set the count to be whatever is the count of the aws_lambda_function.example
, which tells Terraform that we intend for the counts of these to always match. That connection helps Terraform understand how to resolve situations where you increase or reduce the count, by hinting that the resulting create/destroy actions will need to happen in a particular order in order to be valid. We then use count.index
to refer to indices of the other resource, which in this case will only ever be zero but again helps Terraform understand our intent during validation.
The lambda_function
nested block inside aws_s3_bucket_notification
requires a slightly different strategy, since in that case we're not creating a separate resource instance per lambda function but instead just generating some dynamic configuration blocks inside a single resource instance. For that situation, we can use dynamic
blocks which serve as a sort of macro for generating multiple blocks based on elements of a collection:
resource "aws_s3_bucket_notification" "bucket_notification" {
bucket = aws_s3_bucket.example_bucket.id
dynamic "lambda_function" {
for_each = aws_lambda_function.example
content {
# "lambda_function" in this block is the iterator
# symbol, so lambda_function.value refers to the
# current element of aws_lambda_function.example.
lambda_function_arn = lambda_function.value.arn
# ...
}
}
}
Again this is relying on the fact that aws_lambda_function.example
is a list of objects, but in a different way: we ask Terraform to generate a lambda_function
block for each element of aws_lambda_function.example
, setting lambda_function.value
to the whole aws_lambda_function
object corresponding to each block. We can therefore access the .arn
attribute from that object to get the corresponding ARN that we need to populate the lambda_function_arn
argument inside the block.
Again, for this case there will only ever be zero or one lambda function objects and therefore only zero or one lambda_function
blocks, but in both cases this pattern generalizes to other values of count
, ensuring that all of these will stay aligned as your configuration evolves.
Upvotes: 3
Reputation: 397
You can use the same count variable on multiple resources. A nicer and clear way would be to add all resources into a module, if that is possible in your code. https://www.terraform.io/docs/language/meta-arguments/count.html
Upvotes: 4