Lab description
In this lab we learn about implicit dependencies in Terraform.
Understand how implict dependencies work
Setup
Make sure you are in the correct folder:
1
cd ~/terraform-labs
1
cd ~/terraform-labs
If you were unable to complete the last lab, you can find a copy of the files in the solutions folder
1. Create a vnet for every resource group we’ve been creating
-
Add a new variable to
variables.tf
so it can accept some vnet specific detailsNotice the usage of a complex type here
1 2 3 4 5 6 7 8 9 10 11 12
variable "virtual_networks" { type = map(object({ name = string resource_group_key = string address_space = list(string) subnets = map(object({ name = optional(string) address_prefix = string })) })) description = "The virtual networks to deploy" }
NOTE: The
optional
function is used to indicate that the value is not required. This is useful when you want to allow a value to be omitted from the configuration to provide a sensisble default. In this case the subnet name is optional. -
Provide an input for the
virtual_networks
variable interraform.tfvars
.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
virtual_networks = { dev = { name = "vnet-dev" resource_group_key = "dev" address_space = ["10.0.0.0/16"] subnets = { subnet1 = { name = "subnet-dev-1" address_prefix = "10.0.0.0/24" } } } staging = { name = "vnet-staging" resource_group_key = "staging" address_space = ["10.1.0.0/16"] subnets = { subnet1 = { name = "subnet-staging-1" address_prefix = "10.1.0.0/24" } } } prod = { name = "vnet-prod" resource_group_key = "prod" address_space = ["10.2.0.0/16"] subnets = { subnet1 = { address_prefix = "10.2.0.0/24" } subnet2 = { address_prefix = "10.2.1.0/24" } } } }
NOTE: The prod subnets do not have a name specified. This is because the name is optional and we’ll us ethe key to create the name.
-
Update the locals block to
main.tf
to format the subnetsMake sure to replace the contents of the
locals
block with the following:1 2 3 4 5 6 7 8 9 10 11 12 13
locals { subnets = { for subnet in flatten([ for virtual_network_key, virtual_network_value in var.virtual_networks : [ for subnet_key, subnet_value in virtual_network_value.subnets : { composite_key = "${virtual_network_key}-${subnet_key}" name = subnet_value.name == null ? "${virtual_network_value.name}-${subnet_key}" : subnet_value.name address_prefix = subnet_value.address_prefix resource_group_name = azurerm_resource_group.demo[virtual_network_value.resource_group_key].name virtual_network_name = azurerm_virtual_network.demo[virtual_network_key].name } ] ]) : subnet.composite_key => subnet } }
Take note of the following:
- The ternary expression is used to provide a default value if the value is not set. In this case we are using the subnet key to create a default name.
- The expression for the resource group and virtual network names are creating implicit dependencies on the resource groups and virtual networks.
- We are using a nested
for
expression to iterate over the virtual networks and subnets to create a single set of subnets. We use theflatten
function to convert the nested list into a single list.
-
Add new resource blocks to
main.tf
to create the virtual networks and subnets1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
resource "azurerm_virtual_network" "demo" { for_each = var.virtual_networks name = each.value.name address_space = each.value.address_space location = var.region resource_group_name = azurerm_resource_group.demo[each.value.resource_group_key].name } resource "azurerm_subnet" "demo" { for_each = local.subnets name = each.value.name resource_group_name = each.value.resource_group_name virtual_network_name = each.value.virtual_network_name address_prefixes = [each.value.address_prefix] }
Take note of the following:
- The
resource_group_name
of the virtual network is set to the name of the resource group. This creates an implicit dependency on the resource group.
- The
3. Plan and apply
-
Run a
terraform plan
.The output should look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
Terraform will perform the following actions: # azurerm_subnet.demo["dev-subnet1"] will be created + resource "azurerm_subnet" "demo" { + address_prefixes = [ + "10.0.0.0/24", ] + default_outbound_access_enabled = true + id = (known after apply) + name = "subnet-dev-1" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies_enabled = true + resource_group_name = "contoso_research_dev_rg" + virtual_network_name = "vnet-dev" } # azurerm_subnet.demo["prod-subnet1"] will be created + resource "azurerm_subnet" "demo" { + address_prefixes = [ + "10.2.0.0/24", ] + default_outbound_access_enabled = true + id = (known after apply) + name = "vnet-prod-subnet1" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies_enabled = true + resource_group_name = "contoso_research_prod_rg" + virtual_network_name = "vnet-prod" } # azurerm_subnet.demo["prod-subnet2"] will be created + resource "azurerm_subnet" "demo" { + address_prefixes = [ + "10.2.1.0/24", ] + default_outbound_access_enabled = true + id = (known after apply) + name = "vnet-prod-subnet2" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies_enabled = true + resource_group_name = "contoso_research_prod_rg" + virtual_network_name = "vnet-prod" } # azurerm_subnet.demo["staging-subnet1"] will be created + resource "azurerm_subnet" "demo" { + address_prefixes = [ + "10.1.0.0/24", ] + default_outbound_access_enabled = true + id = (known after apply) + name = "subnet-staging-1" + private_endpoint_network_policies = "Disabled" + private_link_service_network_policies_enabled = true + resource_group_name = "contoso_research_staging_rg" + virtual_network_name = "vnet-staging" } # azurerm_virtual_network.demo["dev"] will be created + resource "azurerm_virtual_network" "demo" { + address_space = [ + "10.0.0.0/16", ] + dns_servers = (known after apply) + guid = (known after apply) + id = (known after apply) + location = "northeurope" + name = "vnet-dev" + resource_group_name = "contoso_research_dev_rg" + subnet = (known after apply) } # azurerm_virtual_network.demo["prod"] will be created + resource "azurerm_virtual_network" "demo" { + address_space = [ + "10.2.0.0/16", ] + dns_servers = (known after apply) + guid = (known after apply) + id = (known after apply) + location = "northeurope" + name = "vnet-prod" + resource_group_name = "contoso_research_prod_rg" + subnet = (known after apply) } # azurerm_virtual_network.demo["staging"] will be created + resource "azurerm_virtual_network" "demo" { + address_space = [ + "10.1.0.0/16", ] + dns_servers = (known after apply) + guid = (known after apply) + id = (known after apply) + location = "northeurope" + name = "vnet-staging" + resource_group_name = "contoso_research_staging_rg" + subnet = (known after apply) } Plan: 7 to add, 0 to change, 0 to destroy.
-
Run a
terraform apply -auto-approve
.
3. Verify
- Have a look at the virtual networks and subnets in the Azure portal.
4. Commit your code
Commit your code into git.
5. Recap
Here, we’ve created a vnet for each of our resource groups by applying the concepts covered so far.
Back to Lab Index