Hi,
So typically, when using a module to create resources, the module will also define a set of ‘outputs’ which you can then refer to in the calling/root module.
It’s not 100% clear, but it looks like the main.tf you show is the module main.tf (./modules/vnet/main.tf
)
What you need to do as part of your module is define some outputs to return useful attributes. By convention these would be in an outputs.tf file and might look like this for a module deploying a single VNet and all of its subnets:
./modules/vnet/outputs.tf
:
output "id" {
value = azurerm_virtual_network.vnet.id
description = "Vnet id"
}
output "subnets" {
value = azurerm_virtual_network.vnet.subnet
description = "The subnets within the virtual network"
}
In the calling/root module you would then refer to these as follows:
resource "azurerm_network_interface" "example" {
name = "example-nic"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
ip_configuration {
name = "internal"
subnet_id = module.vnet.subnets[index].id
private_ip_address_allocation = "Dynamic"
}
}
However, you specifically ask to be able to refer to the subnets using the subnet name - a ‘key’ rather than an ‘index’.
In your current implementation (defining the subnets inline with the virtual_network
resource) this is not really possible. As the subnets are created by your dynamic block and therefore an array/list of the subnets rather than a map.
My suggestion here is to look at changing your code to use the stand-alone subnet resource. Check here the note blocks on the virtual network resource in the documentation here: : azurerm_virtual_network | Resources | hashicorp/azurerm | Terraform | Terraform Registry
Ans also provide the subnet details as a map of objects rather than a list of objects for the following reasons:
- You will be able to remove the dynamic block from your vnet resource. Dynamic blocks can make it difficult to read, understand and maintain your code so the advice is to use them only when necessary
- You will be able to refer to subnets using a string/name as the ‘key’, rather than just a number.
So you will remove your dynamic block from your VNET resource and add a new
azurerm_subnet
resource that might look something like this:
resource "azurerm_subnet" "subnets" {
for_each = var.vnet_settings.subnets
name = each.key
resource_group_name = var.vnet_settings.resource_group_name
virtual_network_name = azurerm.vnet_settings.name
address_prefixes = each.value.address_prefixes
}
The variable part would be as follows (assuming the key you use for the map will be the name of the subnet):
subnets = map(object({
prefix = string
}))
So set similar to:
subnets = {
"myvmsubnet" = {
prefix = "10.0.0.0/24"
}
"mystoragesubnet" = {
prefix = "10.0.10.0/24"
}
}
These can then be output:
output "subnets" {
value = azurerm_virtual_network.subnets
description = "The subnets within the virtual network"
}
And referenced:
module.vnet.subnets["{key}"].id
such as:
module.vnet.subnets["mystoragesubnet"].id
Note that the above is not a drop-in solution for your module, but should guide you to what you need to do.
Some other general points:
-
I notice you are using the ‘count’ meta argument a lot in your code. Take a look at the for_each argument (refer to the docs for both count and for_each). In your use case (and many others with the same approach) you are at risk of destroying and recreating resources as they are based upon an index, starting from 0, rather than key. If for some reason order of the list is changed (eg. adding or removing a subnet anywhere other than at the end of the list), terraform will force replacement (destroy and recreate) of all resources of which the index in the list has changed. This can cause some big issues!
Take a look at this article which goes into count vs. for_each and risks in more detail than I have: Terraform — for_each vs count… Count | by Jacek Kikiewicz | Medium
-
I expect you are creating this module for your own education and learning? If not, then consider looking at the terraform registry for already published modules that already do what you need for well defined elements such as this. They can also be reviewed to help you in learning terraform and understanding how to write a module for the resources - Here is the most popular module for Azure VNET : Azure/vnet/azurerm | Terraform Registry - Note that this module also transitioned from using count
to for_each
when it became available.
-
Lastly - when posting code snippets try and use the preformatted text format and other formatting available in the forum as it makes your post easier to read and follow and aids in properly formatting the code (with highlighting)
Hope that helps.
Happy Terraforming!