For syntax problem

Hi,

I have two complex objects that I’ve “merged” based on a unique key, which gives me the desired result, however, I now need to create attributes and I’m having a hard time getting the syntax right, incorportating the new attribute and the if clause in local.vnet_data.subnet_data.

locals:

locals {
  search      = "\\d{0,3}" #Finds nnn in 12/24 (Last octet)
  
  subnet_data = flatten([
    for instance_id, settings in var.network_data : [
      for netnum, subnet in settings : {
        instance_id          = "${instance_id}.${netnum + 1}"
        subnet_object        = subnet.subnets
      }
    ]
  ])
  
  vnet_data   = flatten([
    for vnet_instance_id, vnet in module.virtual_network.object : {
      instance_id     = vnet_instance_id
      virtual_network = vnet
      subnet_data     = flatten([
        for netnum, subnet in local.subnet_data : 
          subnet.subnet_object if subnet.instance_id == vnet_instance_id
          
          #Problematic line:
          net_prefix = cidrsubnet(vnet.address_block, subnet.newbits, netnum)
      ])
    }
  ])
}

var.network_data comes from a .tfvars file that contains data used to build subnets in the resource for creating subnets as shown below:
module.virtual_network.object just creates the vnet, with no subnets.

Subnet resource (not working):

resource "azurerm_subnet" "pool" {
  for_each             = {
    for ns, vnet in local.vnet_data : 
    "${vnet.instance_id}.${ns}" => vnet
  }
  name                  = format("%s%s%s%03d%s%03d", "nsb_", each.value.purpose, "_", each.value.octet_3, "_", each.value.octet_4)
  resource_group_name   = each.value.virtual_network.resource_group_name
  virtual_network_name  = each.value.virtual_network.name
  address_prefix        = each.value.net_prefix
}

Referencing the address_prefix attribute from azurerm_subnet.pool resource, each.value.net_prefix doesn’t work because I don’t have the right syntax for the net_prefix attribute in local.vnet_data.

How do I incorportate the if “filter” and the net_prefix attribute in the same local block?

I have tried using matchkeys() function instead, but as I need to create attribute values inside the “for subnet” loop, I can’t see it will work.

I’ve also tried writing the code like:

for vnet in module_virtual_network.object : [
  for subnet in local.subnet_data : {...}
]

But, I can’t work out how to use the if clause, I just get syntax errors.

Any help, greatly apreciated.
TIA.

Hi @arcotek-ltd!

The syntax for a for expression producing a list with an if clause is structured like this:

'['
  'for' <identifier> ',' <identifier> 'in' <expression> ':' 
  <expression>
  'if' <expression>
']'

Hopefully the above “pseudo-BNF” notation is intuitive; the main thing I’m trying to show in the above is that the if clause must come after the result expression, not inside it.

It looks like you want to create new objects that have all of the attributes from local.subnet_data but also a new net_prefix attribute. Here’s one way to achieve that:

[
  for netnum, subnet in local.subnet_data :
  merge(subnet.subnet_object, {
    net_prefix = cidrsubnet(
      vnet.address_block, subnet.subnet_object.newbits, netnum,
    )
  })
  if subnet.instance_id == vnet_instance_id
]

Note that the if clause appears after the expression that produces the list element value, and so this should be consistent with the required syntax for a for expression as shown above.

2 Likes