Nov 13 2022

Convertir une Map de Maps en Map Unique

Publié par à 8:27 sous DevOps,Terraform

..Ou comment éviter le message d’erreur ‘Call to function « merge » failed: arguments must be maps or objects, got « tuple ».’. L’exemple avec une map de maps.


Problème à la Création d’une Map

Voici une structure de données typique à 2 niveaux avec des sous-groupes qui contiennent des utilisateurs, eux-mêmes appartenant à des départements:

locals {
   groups = {
      it = {
         admin   = ["it1","it2"]
         editors = ["it3","it4"]
      },
      accounts = {
         editors = ["account1","account2"]
         viewers = ["account3","account4"]
      }
   }
}


La structure devra être nivelée (flatten) dans de nombreux cas pour créer des resources Terraform.
Notre cible est une map de sous-groupes uniques departement_sous-group = [ « user1 », « user2 » ]. Dans notre exemple:

subgroups = {
  "accounts_editors" = [
    "account1",
    "account2",
  ]
  "accounts_viewers" = [
    "account3",
    "account4",
  ]
  "it_admin" = [
    "it1",
    "it2",
  ]
  "it_editors" = [
    "it3",
    "it4",
  ]
}


C’est assez simple d’obtenir une liste de maps distinctes en nivelant les listes résultantes d’une double boucle:

subgroups = flatten([
   for group,subgroups in local.groups : [
      for subgroup, users in subgroups : {
         "${group}_${subgroup}" = users
      }
   ]
])
# output:
subgroups = [
  {
    "accounts_editors" = [
      "account1",
      "account2",
    ]
  },
  {
    "accounts_viewers" = [
      "account3",
      "account4",
    ]
  },
  {
    "it_admin" = [
      "it1",
      "it2",
    ]
  },
  {
    "it_editors" = [
      "it3",
      "it4",
    ]
  },
]

Tout ce qu’il nous reste à faire est de fusionner ces maps en une map unique, mais ce faisant, le message d’erreur nous est retourné:
‘Call to function « merge » failed: arguments must be maps or objects, got « tuple ».’

Call to function "merge" failed: arguments must be maps or objects, got "tuple"
Call to function « merge » failed: arguments must be maps or objects, got « tuple »


2 recours possibles: le moche et l’élégant.


La Solution Moche : Une Autre Boucle Terraform


La 1re solution qui vient à l’esprit est de générer la nouvelle map via une autre boucle for. Cela nous amène à 3 boucles, et ne semble pas très logique alors qu’un simple merge ferait le travail. Chaque map contient un élément seulement, donc nous prenons les 1res clé et valeur.

subgroups = { for subgroup in flatten([
   for group,subgroups in local.groups : [
      for subgroup, users in subgroups : {
         "${group}_${subgroup}" = users
      }
   ]
]) : keys(subgroup)[0] => values(subgroup)[0] }


La Solution Elégante : la Fonction Expansion


C’est beaucoup plus court que la solution précédente:

subgroups = merge(flatten([
   for group,subgroups in local.groups : [
      for subgroup, users in subgroups : {
         "${group}_${subgroup}" = users
      }
   ]
])...)

Le résultat est exactement le même mais qu’est-ce qui a changé? Juste les 3 points…
La fonction Expansion prend chaque élément d’une liste et led passe à la fonction appelante.



No responses yet

Comments RSS

Leave a Reply