Search code examples
terraformnested-loopsterraform-provider-azure

Terraform Nested Loops 1.12


I am trying to implement nested for loops using Terraform 1.12 in order to loop through Azure users, each of which can have one or more values attached. The variable used to represent this list is of type map(list(string)) and looks something like this:

VirtualMachine = {
  app = {
    Size = "Standard_B4ms"
    Disks = {
      OS = {
        Cache = "ReadWrite"
        Size  = 128
        Type  = "Premium_LRS"
      }
      Data = {
        Cache = "ReadWrite"
        Size  = 64
        Type  = "Premium_LRS" 
      }
    }
    Image = {
      Publisher = "MicrosoftWindowsServer"
      Offer     = "WindowsServer"
      Sku       = "2022-datacenter-azure-edition"
      Version   = "latest"
    }
  }
}

I am attempting construct that list and store it in a local variable like so, where

  vmDisks = {
    for key, value in flatten([
      for vmKey, vm in var.VirtualMachine : [
        for diskKey, disk in vm.Disks.Data : {
          VmId   = vmKey
          DiskId = diskKey
          Cache  = disk.Cache
          Type   = disk.Type
          Size   = disk.Size
          Lun    = 1 + index(keys(vm.Disks.Data), diskKey)
      }
    ]
    if contains(keys(vm.Disks), "Data")
    ]) : "${value.VmId}.${value.DiskId}" => value
  }

However, I am getting errors when attempting to access the values in that nested list.

Error: Unsupported attribute │ │ on locals.tf line 48, in locals: │ 48: Cache = disk.Cache │ │ Can't access attributes on a primitive-typed value (string)

can you help me here?

I have tried to pass diskKey[0] with the reference local.association-list[count.index][0] and fails at terraform plan stage


Solution

  • In your inner loop:
    for diskKey, disk in vm.Disks.Data
    The disk is not what you think, here is an example:

    locals {
      vmDisks = {
        for key, value in flatten([
          for vmKey, vm in var.VirtualMachine : [
            for diskKey, disk in vm.Disks.Data : {
              VmId   = vmKey
              DiskId = diskKey
              disk  = disk
              Lun    = 1 + index(keys(vm.Disks.Data), diskKey)
            }
          ]
          if contains(keys(vm.Disks), "Data")
        ]) : "${value.VmId}.${value.DiskId}" => value
      }
    }
    
    output "test" {
        value = local.vmDisks
    }
    
    variable "VirtualMachine" {
      default = {
        app = {
          Size = "Standard_B4ms"
          Disks = {
            OS = {
              Cache = "ReadWrite"
              Size  = 128
              Type  = "Premium_LRS"
            }
            Data = {
              Cache = "ReadWrite"
              Size  = 64
              Type  = "Premium_LRS"
            }
          }
          Image = {
            Publisher = "MicrosoftWindowsServer"
            Offer     = "WindowsServer"
            Sku       = "2022-datacenter-azure-edition"
            Version   = "latest"
          }
        }
      }
    }
    

    the output of that is this:

      + test = {
          + app.Cache = {
              + DiskId = "Cache"
              + Lun    = 1
              + VmId   = "app"
              + disk   = "ReadWrite"
            }
          + app.Size  = {
              + DiskId = "Size"
              + Lun    = 2
              + VmId   = "app"
              + disk   = 64
            }
          + app.Type  = {
              + DiskId = "Type"
              + Lun    = 3
              + VmId   = "app"
              + disk   = "Premium_LRS"
            }
        }
    

    As you can see the disk is just a value not an object