Search code examples
azureterraformterraform-provider-azureterraform0.12+azure-rm

How to use output value in same root module for creating another resource


Context: This is continuation of below post which I raised Issue while creating multiple subnets using for_each in Terraform

Objective: How to use output value of one resource created and use that for creating another resource in same root module

What I tried:

resource "azurerm_virtual_network" "vnet" {
  name                = var.hub_vnet_name
  location            = azurerm_resource_group.rg[0].location
  resource_group_name = azurerm_resource_group.rg[0].name
  for_each = {for k,v in var.vnet_address_space: k=>v if k == "${var.env}"}
  address_space       =  each.value
  dns_servers         = var.dns_servers
  tags     = {
    environment = "${var.env}"
    costcentre = "14500"
  }
  dynamic "ddos_protection_plan" {
    for_each = local.if_ddos_enabled

    content {
      id     = azurerm_network_ddos_protection_plan.ddos[0].id
      enable = false
    }
  }
}

output "azurerm_vnets_names" {
    value = values(azurerm_virtual_network.vnet)[*].name
             
}

Till above point its working and I see output of as

Outputs:

azurerm_vnets_names = [
  "vnet-hub",
]

Now as next step I am trying to create Subnets in loop as below

tfvars.json:

"subnets" : {
        "Dev" :
        [  
        {"gw_snet":{
          "name"                 : "GatewaySubnet",
          "address_prefixes"     : ["10.1.1.0/24"]
        },
        "dns-snet" : {
          "name"                 : "InboundDNSSubnet",
          "address_prefixes"     : ["10.1.2.0/24"]
        },
        "common_snet" : {
          "name"                 : "Common",
          "address_prefixes"     : ["10.1.3.0/24"]
        },
        "clientdata_snet" : {
          "name"                 : "ClientDataSubnet",
          "address_prefixes"     : ["10.1.4.0/20"]
        }}
        ],
        "Stage" :
        [  
        {"gw_snet":{
          "name"                 : "GatewaySubnet",
          "address_prefixes"     : ["10.2.1.0/24"]
        },
        "dns-snet" : {
          "name"                 : "InboundDNSSubnet",
          "address_prefixes"     : ["10.2.2.0/24"]
        },
        "common_snet" : {
          "name"                 : "Common",
          "address_prefixes"     : ["10.2.3.0/24"]
        },
        "clientdata_snet" : {
          "name"                 : "ClientDataSubnet",
          "address_prefixes"     : ["10.2.4.0/20"]
        }}
        ],
        "Prod" :
        [  
        {"gw_snet":{
          "name"                 : "GatewaySubnet",
          "address_prefixes"     : ["10.3.1.0/24"]
        },
        "dns-snet" : {
          "name"                 : "InboundDNSSubnet",
          "address_prefixes"     : ["10.3.2.0/24"]
        },
        "common_snet" : {
          "name"                 : "Common",
          "address_prefixes"     : ["10.3.3.0/24"]
        },
        "clientdata_snet" : {
          "name"                 : "ClientDataSubnet",
          "address_prefixes"     : ["10.3.4.0/20"]
        }}
        ]
      }  

In my main.tf:

locals {
   net_subnets = merge([
    for env, network in var.subnets : {
      for k, v in network[0] :
      "${k}-${v.name}" => {
        subnet_name      = v.name
        address_prefixes = v.address_prefixes
      } if env == "Dev"
  }]...)
}


#Creating subnets

resource "azurerm_subnet" "mysubnet" {
  for_each             = local.net_subnets
  name                 = each.value.subnet_name
  address_prefixes     = each.value.address_prefixes
  virtual_network_name = azurerm_virtual_nework.vnet.name
  resource_group_name  = var.resource_group_name
}

Now below line is erroring out

virtual_network_name = azurerm_virtual_nework.vnet.name

saying " since I used for_each in creating vnet I cannot use that above way

Now since I see output variable which I defined above which is azurerm_vnets_names , I tried to refer that as below

virtual_network_name = azurerm_vnets_names

it didnt work

Then

I tried to add datasource

data "azurerm_virtual_network" "vnet" {
  name                = "vnet-hub"
  resource_group_name = "hub"
}

then tried below:

virtual_network_name = data.azurerm_virtual_nework.vnet.name

Again error says that.. Its not declared.

I tried below one also, didnt work

  virtual_network_name = azurerm_virtual_network.vnet[*].name

Please help me with identifying issue.


Solution

  • This is erroring out because azurerm_virtual_nework.vnet is a set, not a single value. You created azurerm_virtual_nework.vnet with a for_each, so Terraform thinks there can be more than one azurerm_virtual_nework.vnet resource, and you aren't telling it which one to use. This should be clear if you look at the error message Terraform is giving you.

    virtual_network_name = azurerm_virtual_nework.vnet.name
    

    This is invalid Terraform syntax:

    virtual_network_name = azurerm_vnets_names
    

    Outputs are only to be referenced by parent modules. In the root module outputs are only used for outputting things to the output log of your terraform apply run. You don't declare outputs to use in the same module that you declare them in.


    The fix is to actually pull out the value you need from the azurerm_virtual_nework.vnet set:

    virtual_network_name = azurerm_virtual_nework.vnet[var.env].name
    

    Although, I think you could clean up the code even more by not using a for_each at all in your azurerm_virtual_nework.vnet resource, and just lookup the value from your map instead of greatly overcomplicating everything by trying to loop over it your map with an if statement: var.vnet_address_space[var.env].