Saya memiliki modul Terraform yang menghasilkan daftar keluaran peta:

object_ids = [
  {
    "object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
    "upn" = "john@domain.com"
    "user" = "john"
  },
  {
    "object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
    "upn" = "martin@domain.com"
    "user" = "martin"
  },
]

Menggunakan for_each saya dapat mengulang satu nilai untuk membangun sumber daya ini:

resource "azurerm_role_assignment" "subread" {
    for_each = toset(module.user.map_object_ids[*].object_id)
    scope                = data.azurerm_subscription.primary.id
    role_definition_name = "Reader"
    principal_id         = each.value
}

Namun saya tidak tahu cara mengulang lebih dari satu nilai.

Saya mencoba yang berikut ini untuk sumber daya lain yang membutuhkan 2 nilai berbeda dari output:

resource "azurerm_role_assignment" "contribrg" {
    scope                = [for map in module.user.map_object_ids[*]: "${data.azurerm_subscription.primary.id}/resourceGroups/${lookup(map,"user")}"]
    role_definition_name = "Contributor"
    principal_id         = [for map in module.user.map_object_ids[*]: lookup(map,"object_id")]
}

Mendapat kesalahan berikut:

Error: Incorrect attribute value type
module.user.map_object_ids is tuple with 2 elements
Inappropriate value for attribute "scope": string required.
Inappropriate value for attribute "principal_id": string required.
2
nibarras 1 Juli 2020, 17:32

1 menjawab

Jawaban Terbaik

Persyaratan mendasar dari sumber daya for_each adalah bahwa koleksi yang Anda gunakan harus memiliki satu elemen per instance yang ingin Anda buat, jadi tidak mungkin untuk mengulang berdasarkan lebih dari satu nilai, tapi untungnya menurut saya itu tidak' t sebenarnya apa yang Anda minta di sini.

Alih-alih, sepertinya Anda ingin memiliki satu instance untuk setiap elemen module.user.map_object_ids, jadi satu-satunya masalah tambahan yang perlu kita tangani adalah for_each mengharapkan untuk diberikan peta objek daripada daftar objek, sehingga dapat menggunakan kunci peta sebagai pengidentifikasi untuk setiap instance.

Kita dapat mengonversi daftar objek menjadi peta objek dengan menggunakan for ekspresi, meskipun kita harus mengidentifikasi salah satu atribut dari objek bersarang yang akan berfungsi sebagai kunci unik untuk setiap elemen. Saya akan menggunakan user di sini karena sepertinya ini adalah pengidentifikasi unik yang dapat dipahami manusia dan dipilih oleh konfigurasi:

resource "azurerm_role_assignment" "contribrg" {
  for_each = { for obj in module.user.map_object_ids : obj.user => obj }

  scope                = "${data.azurerm_subscription.primary.id}/resourceGroups/${each.value.user}"
  role_definition_name = "Contributor"
  principal_id         = each.value.object_id
}

Ekspresi for di atas akan memproyeksikan daftar objek Anda ke dalam peta objek, seperti ini:

{
  "john" = {
    "object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
    "upn" = "john@domain.com"
    "user" = "john"
  }
  "martin" = {
    "object_id" = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
    "upn" = "martin@domain.com"
    "user" = "martin"
  }
}

Kemudian di dalam ekspresi argumen sumber daya each.key akan merujuk ke nama pengguna (karena mereka sekarang adalah kuncinya) sementara each.value akan merujuk ke objek, jadi kita dapat menggunakan each.value.object_id untuk mendapatkan yang sesuai pengenal objek.

Dari sini, Terraform akan berencana untuk membuat instance sumber daya dengan alamat berikut:

  • azurerm_role_assignment.contribrg["john"]
  • azurerm_role_assignment.contribrg["martin"]

Catatan tambahan: Saya merasa sedikit membingungkan bahwa output Anda bernama object_ids ketika tidak hanya mengembalikan id. Mungkin lebih jelas untuk menamakannya objects.

1
Martin Atkins 1 Juli 2020, 23:31