Need help to call data source in for_each - terraform

I am replacing count with for_each for following code. Need help in referring index of resource when calling data source of azurerm_monitor_diagnostic_categories under dynamic "log".
resource "azurerm_monitor_diagnostic_setting" "diag" {
count = length(var.resource_id)
name = "diag"
target_resource_id = var.resource_id[count.index]
log_analytics_workspace_id = var.log_analytics_workspace_id
dynamic "log" {
for_each = data.azurerm_monitor_diagnostic_categories.resource[count.index].logs
content {
category = log.value
enabled = true

Was looking for the same information when finding your question.
The below works for me:
dynamic "log" {
for_each = [for lg in data.azurerm_monitor_diagnostic_categories.webui.logs : {
lg_name = lg
}
]
content {
category = log.value.lg_name
enabled = true
retention_policy {
enabled = false
}
}
}

Related

Azure Storage (Blob, Queue, Table) Logging in Terraform with for_each and locals

I am writing Terraform code to enable logging on Azure Storage Blob, Queue and Table types. With my current code, I need to fetch data for each Storage type,say for example Blob, and use it to get it's log and metrics details.
Is there any way I could use for_each and locals to avoid repeating the same block of code for each Storage type. Below is what the code looks like now for Blob type,
data "azurerm_monitor_diagnostic_categories" "storage_blob" {
resource_id = "${azurerm_storage_account.stamp.id}/blobServices/default/"
}
resource "azurerm_monitor_diagnostic_setting" "storage_blob" {
name = "storageblobladiagnostics"
target_resource_id = "${azurerm_storage_account.stamp.id}/blobServices/default/"
log_analytics_workspace_id = azurerm_log_analytics_workspace.stamp.id
dynamic "log" {
iterator = entry
for_each = data.azurerm_monitor_diagnostic_categories.storage_blob.logs
content {
category = entry.value
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
dynamic "metric" {
iterator = entry
for_each = data.azurerm_monitor_diagnostic_categories.storage_blob.metrics
content {
category = entry.value
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
}
The below implementation doesn't seem to work as the data block is not able handle the for_each expression in the dynamic block
locals {
storage = ["blobServices", "tableServices", "queueServices"]
}
data "azurerm_monitor_diagnostic_categories" "storage_blob" {
resource_id = "${azurerm_storage_account.stamp.id}/${each.key}/default/"
}
resource "azurerm_monitor_diagnostic_setting" "storage_blob" {
for_each = toset(local.storage)
name = "storageblobladiagnostics"
target_resource_id = "${azurerm_storage_account.stamp.id}/${each.key}/default/"
log_analytics_workspace_id = azurerm_log_analytics_workspace.stamp.id
dynamic "log" {
iterator = entry
for_each = data.azurerm_monitor_diagnostic_categories.storage_blob.logs
content {
category = entry.value
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
dynamic "metric" {
iterator = entry
for_each = data.azurerm_monitor_diagnostic_categories.storage_blob.metrics
content {
category = entry.value
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
}
In order for this to work, you would have to adjust the code slightly. In your example, the data source is not using for_each, so it cannot be used the way you want. The adjustment is as follows:
locals {
storage = ["blobServices", "tableServices", "queueServices"]
}
data "azurerm_monitor_diagnostic_categories" "storage_blob" {
for_each = toset(local.storage)
resource_id = "${azurerm_storage_account.stamp.id}/${each.key}/default/"
}
resource "azurerm_monitor_diagnostic_setting" "storage_blob" {
for_each = toset(local.storage)
name = "storageblobladiagnostics"
target_resource_id = "${azurerm_storage_account.stamp.id}/${each.key}/default/"
log_analytics_workspace_id = azurerm_log_analytics_workspace.stamp.id
dynamic "log" {
iterator = entry
for_each = "${data.azurerm_monitor_diagnostic_categories.storage_blob[each.key].logs}"
content {
category = entry.value
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
dynamic "metric" {
iterator = entry
for_each = "${data.azurerm_monitor_diagnostic_categories.storage_blob[each.key].metrics}"
content {
category = entry.value
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
}

How to use Terraform for_each resource block and count resource block

I am having a azurerm_postgresql_flexible_server resource using count and azurerm_postgresql_flexible_server_configuration using fore each. Please find the below code.
config= [{
"name" = shared_preload_libraries,
"values" = ["EXAMPLE1", "EXAMPLE2"]
},
{
"name" = "azure.extensions"
"values" = ["EXAMPLE1", "EXAMPLE2", "EXAMPLE3"]
}]
locals {
flat_config = merge([
for single_config in var.config: {
for value in single_config.values:
"${single_config.name}-${value}" => {
"name" = single_config.name
"value" = value
}
}
]...)
}
Below is my for_each resource
resource "azurerm_postgresql_flexible_server_configuration" "example" {
for_each = local.flat_config
name = each.value.name
server_id = azurerm_postgresql_flexible_server.example.id
value = each.value.value
}
currently I am having two azurerm_postgresql_flexible_server resources. azurerm_postgresql_flexible_server.example[0] and azurerm_postgresql_flexible_server.example[1]. Could you please let me know if there is a possibility to include some alternative options like count?
Splat Expressions did not work.
If you want to apply your two azurerm_postgresql_flexible_server for each instance of azurerm_postgresql_flexible_server_configuration, you need one more extra level of flattening:
locals {
flat_config = merge(flatten([
for single_config in var.config: [
for value in single_config.values: {
for idx, server in azurerm_postgresql_flexible_server.example:
"${single_config.name}-${value}-${idx}" => {
"name" = single_config.name
"value" = value
"flexible_server" = server
}
}
]
])...)
}
then
resource "azurerm_postgresql_flexible_server_configuration" "example" {
for_each = local.flat_config
name = each.value.name
server_id = each.value.flexible_server.id
value = each.value.value
}

How to create Iterative Loop in Terraform

I have around 50 resources that I create in a Terraform script.
I need now to add diagnostic logging for each resource.
The following code is what I use:
data "azurerm_monitor_diagnostic_categories" "vnet-spoke01" {
resource_id = module.MOD-VNET-SPOKE01.id
}
resource "azurerm_monitor_diagnostic_setting" "vnet-spoke01" {
name = "diag-${module.MOD-VNET-SPOKE01.vnetName}"
target_resource_id = module.MOD-VNET-SPOKE01.id
log_analytics_workspace_id = module.MOD-LOG-ANALYTICS-WORKSPACE.id
dynamic "log" {
for_each = data.azurerm_monitor_diagnostic_categories.vnet-spoke01.logs
content {
category = log.value
retention_policy {
days = 0
enabled = false
}
}
}
dynamic "metric" {
for_each = data.azurerm_monitor_diagnostic_categories.vnet-spoke01.metrics
content {
category = metric.value
retention_policy {
days = 0
enabled = false
}
}
}
}
As you can see, I'm adding VNET of spoke-1 diagnostic settings.
Can someone kindly guide me as to how I can add a for-loop so it goes through each resource (that I'd put in an array or list) and run through it?
e.g.
variable "myResources" {
type = list(string)
default = ["module.MOD-VNET-SPOKE01", "module.MOD-VNET-SPOKE02" etc...]
}
for a in myResources
{
.... execute diagnostic routine
}
How could I do this?
Many thanks
Sadly you can't do that. You can't dynamically resolve strings (e.g. "module.MOD-VNET-SPOKE01") into resource identifiers (e.g. module.MOD-VNET-SPOKE01.id.
Your variable would already have to contain all ids for your loop to work:
variable "myResources" {
type = list(string)
default = ["<id-SPOKE01>", "<id-SPOKE02>", etc...]
}
or through locals:
locals {
myResources = [module.MOD-VNET-SPOKE01.id, module.MOD-VNET-SPOKE02.id etc...]
}

Terraform refactoring for azurerm_dns_txt_record use in a module record block

I've got the following code in a terraform module:
locals {
txt_records = flatten(
[
for i in var.DnsZones :
{
zone_name = i.ZoneName
resource_group_name = i.ResourceGroup
name = "#"
ttl = i.Ttl
records = i.TxtRecords
}
]
)
}
resource "azurerm_dns_zone" "zone" {
count = length(var.DnsZones)
name = var.DnsZones[count.index].ZoneName
resource_group_name = var.DnsZones[count.index].ResourceGroup
}
resource "azurerm_dns_txt_record" "record-txt" {
count = length(local.txt_records)
resource_group_name = local.txt_records[count.index].resource_group_name
zone_name = local.txt_records[count.index].zone_name
ttl = local.txt_records[count.index].ttl
name = local.txt_records[count.index].name
record {
value = local.txt_records[count.index].records[0]
}
record {
value = local.txt_records[count.index].records[1]
}
record {
value = local.txt_records[count.index].records[2]
}
record {
value = local.txt_records[count.index].records[3]
}
record {
value = local.txt_records[count.index].records[4]
}
record {
value = local.txt_records[count.index].records[5]
}
record {
value = local.txt_records[count.index].records[6]
}
depends_on = [azurerm_dns_zone.zone]
}
It doesn't seem like a very clean way of adding record blocks, but i can't find a better way of doing it.
I've tried refactoring it in this way:
resource "azurerm_dns_txt_record" "record-txt" {
count = length(local.txt_records)
resource_group_name = local.txt_records[count.index].resource_group_name
zone_name = local.txt_records[count.index].zone_name
ttl = local.txt_records[count.index].ttl
name = local.txt_records[count.index].name
dynamic "record" {
for_each = local.txt_records[count.index].records
iterator = i
content {
value = i.value
}
}
depends_on = [azurerm_dns_zone.zone]
}
but unfortunately, this results in a single MX record in our DNS where we should have 7 items inserted. It seems that each item gets inserted on top of the previous one.
As you can see each of the record blocks needs to be separated in the resource: MX record resource
Can anyone think of a better way of structuring this terraform?
Your dynamic block should be:
dynamic "record" {
for_each = local.txt_records[count.index].records
content {
value = record.value
}
}
not
dynamic "record" {
for_each = local.txt_records[count.index].records
content {
value = i.value
}
}

Creating a dynamic topic block within aws_s3_bucket_notification resource (Terraform)

I am creating a Terraform module that allows users to specify a map of s3 buckets and the properties of the event notifications they wish to add to those buckets.
The variable that they will pass to the module will look something like the following:
input = {
bucket_1 = {
name = "name-of-bucket-1"
filters = [
{
name = "filter1"
filter_prefix = "/test"
filter_suffix = ".txt"
},
{
name = "filter2"
filter_prefix = ""
filter_suffix = ".gz"
}
]
},
bucket_2 = {
name = "name-of-bucket-2"
log_source_type = "aws:cloudtrail:sandbox"
filters = [
{
name = "filter1"
filter_prefix = ""
filter_suffix = ".gz"
}
]
}
}
The resource block will be created as follows:
resource "aws_s3_bucket_notification" "notification" {
for_each = var.input
bucket = each.value.name
dynamic "topic" {
for_each = each.value.filters
content {
topic_arn = aws_sns_topic.sns_topic_s3[each.key].arn
events = ["s3:ObjectCreated:*"]
filter_prefix = each.value.filters.filter_prefix
filter_suffix = each.value.filters.filter_suffix
}
}
}
Unfortunately, when attempting to run a plan, I am getting the following error:
Error: Unsupported attribute
on modules/aws-splunk-forwarder-s3/main.tf line 26, in resource "aws_s3_bucket_notification" >"splunk_forwarder_s3":
26: filter_suffix = each.value.filters.filter_suffix
|----------------
| each.value.filters is tuple with 2 elements
This value does not have any attributes.
Does anyone have idea how I can achieve this?
Thanks,
Adam
Nevermind everyone... I managed to work it out.
Posting my answer in case anybody else is in the same predicament.
resource "aws_s3_bucket_notification" "notification" {
for_each = var.splunk_s3_input
bucket = each.value.name
dynamic "topic" {
for_each = [for s in each.value.filters: {
suffix = s.filter_suffix
prefix = s.filter_prefix
}]
content {
topic_arn = aws_sns_topic. sns_topic_s3[each.key].arn
events = ["s3:ObjectCreated:*"]
filter_prefix = topic.value.suffix
filter_suffix = topic.value.prefix
}
}
}
My issue was using "each.value" instead of "topic.value" when attempting to reference the values of the dynamic block loop.

Resources