Reputation: 441
This is my code source
resource "aws_s3_bucket_object" "object" {
count = var.s3_create[1] ? 1 : 0
depends_on = [aws_s3_bucket.bucket_backup]
for_each = local.buckets_and_folders
bucket = each.value.bucket_backup
key = format("%s/", each.value.folder)
force_destroy = true
}
In other words, I'm traying to create object aws_s3_bucket_object
depends on variable s3_create
... create if true else not create.
Issue: I am not able to use the combination of both the below syntax in creating the terraform resource and I'm geeting :
Error: Invalid combination of "count" and "for_each"
│
│ on ..\s3\resources.tf line 51, in resource "aws_s3_bucket_object" "object":
│ 51: for_each = local.buckets_and_folders
│
│ The "count" and "for_each" meta-arguments are mutually-exclusive, only one should be used to be explicit about the number of resources to be created.
Upvotes: 13
Views: 21764
Reputation: 79
It is possible to combine "count" and "for_each" in a terraform resource block
But you have to be "dynamic" about it
Here's an example of what I have in place (and working)
resource "azurerm_network_security_group" "nsg-001" {
count = var.nsg-deploy.deploy ? 1 : 0
dynamic "security_rule" {
for_each = local.nsg_001_ruleset_001
content {}
}
Cheers
-=A=-
.
Upvotes: 0
Reputation: 74719
The rule for for_each
is that you should assign it a map or set that has the same number of elements as the number of instances you want to declare.
Thinking about your goal from that standpoint, the solution will involve making your map be empty in situations where you want to declare no instances. The typical way to filter elements from a collection is to write [a for
expression] with an if
clause.
From what you shared in your example I can't tell if local.buckets_and_folders
is a map or a set of strings, so I'll show examples for both...
If it's a map:
for_each = tomap({
for k, v in local.buckets_and_folders : k => v
if var.s3_create[1]
})
If it's a set:
for_each = toset([
for v in local.buckets_and_folders : v
if var.s3_create[1]
])
In both cases the if
clause means that the result will be an empty collection if var.s3_create[1]
is false.
There may be other ways to design your module so that the input and the derived expressions can be simpler, but working within the relatively limited examples you shared the above is the most direct answer to your question. If you'd like to talk about possible ways to simplify this, you could ask a new question on Stack Overflow and include a fuller example of your current code and the underlying requirements this module is intended to meet.
Upvotes: 3
Reputation: 10117
Both count and for_each apply to the whole block. Indenting lines underneath a for_each doesn't impact anything but human readability.
Try using the ternary operator with a for_each instead of a count. If the value is false, return an empty set.
resource "aws_s3_bucket_object" "object" {
for_each = var.s3_create[1] ? tomap({local.buckets_and_folders}) : {}
bucket = each.value.bucket_backup
key = format("%s/", each.value.folder)
depends_on = [aws_s3_bucket.bucket_backup]
force_destroy = true
}
Upvotes: 24