I'm currently writing some Terraform code that deploys Azure Private DNS zones into Azure.
I have successfully deployed the DNS zones using the following code:
dns_zones = [
"domain1.com",
"domain2.com",
"domain3.com",
]
resource "azurerm_private_dns_zone" "dns_zones" {
for_each = toset(var.dns_zones)
name = each.value
resource_group_name = var.resource_group
}
My problem is configuring the the links between the zones and the virtual networks. I need to iterate through the dns_zones list and have a nested loop that then iterates through the vnet_links list and configures the vnet links on the zone.
The following solution works, however it's not very robust as removing configuration from either list will shuffle the index numbers of the list, causing Terraform to delete and re-create the configuration, which is not an option:
vnet_links = [
{
"linkName": "name-of-vnet-link1"
"vnetId": "vnet--resource-id-placeholder1"
},{
"linkName": "name-of-vnet-link2"
"vnetId": "vnet--resource-id-placeholder2"
}
]
resource "azurerm_private_dns_zone_virtual_network_link" "vnet_link" {
count = length(setproduct(var.dns_zones, var.vnet_links))
name = element(setproduct(var.dns_zones, var.vnet_links)[count.index], 1).linkName
resource_group_name = var.resource_group
private_dns_zone_name = element(setproduct(var.dns_zones, var.vnet_links)[count.index], 0)
virtual_network_id = element(setproduct(var.dns_zones, var.vnet_links)[count.index], 1).vnetId
}
I have found that using the setproduct() function below can create a new list containing the data I want to work with, and it was my intention to use this with a for_each rather than a count, but it's not possible to use this with the toset() function, as it only accepts a list of strings.
setproduct(var.dns_zones, var.vnet_links)
Right now i'm a bit stuck where to go with this. I could include the zone information within the vnet_links list, but this would require lot's of duplication which i'd like to avoid. Ideally I would like to be able to find a solution that doesn't require any changes to the dns_zones list, and retains a separate list with the vnet links.
Thanks!
EDIT:
Thanks to Charles for providing a way to format the data. In addition to Charles response, I also needed to create a dynamic map within the for_each loop to use the data. The final solution looks as follows:
dns_zones = [
"domain1.com",
"domain2.com",
"domain3.com",
]
vnet_links = [
{
"linkName": "name-of-vnet-link1"
"vnetId": "vnet--resource-id-placeholder1"
},{
"linkName": "name-of-vnet-link2"
"vnetId": "vnet--resource-id-placeholder2"
}
]
locals {
association = flatten([
for dns_zone in var.dns_zones: [
for link in var.vnet_links: {
zone = dns_zone
vnet_link = link
}
]
])
}
resource "azurerm_private_dns_zone_virtual_network_link" "vnet_link" {
for_each = { for row in local.association:
"${row.zone}_${row.vnet_link.linkName}" => {
zone = row.zone
linkName = row.vnet_link.linkName
vnetId = row.vnet_link.vnetId
}
}
name = each.value.linkName
resource_group_name = var.resource_group
private_dns_zone_name = each.value.zone
virtual_network_id = each.value.vnetId
}