web-dev-qa-db-fra.com

Est-il possible d'aplatir une liste de listes avec Ansible/Jinja2?

Mon problème fondamental est qu’à la création d’un ensemble de serveurs aws, je souhaite les configurer pour qu’ils se connaissent bien.

Lors de la création de chaque serveur, leurs détails sont enregistrés dans une variable 'serveurs' enregistrée (voir ci-dessous). Ce que je veux vraiment pouvoir faire après la création est exécuté comme suit:

- name: Add servers details to all other servers
  lineinfile:
    dest: /path/to/configfile
    line: "servername={{ item.1.private_ip }}"
  delegate_to: "{{ item.0.public_dns_name }}"
  with_nested:
    - list_of_servers
    - list_of_servers

Fournir deux fois la liste à 'with_nested' est ici essentiel.

Obtenir une liste de liste est assez facile à faire avec:

"{{ servers.results | map(attribute='tagged_instances') | list }}"

qui retourne:

[ 
  [ { "private_ip": "ip1", "public_dns_name": "dns1" } , { ... }],
  [ { ... }, { ... } ]
]

mais comment transformeriez-vous cela en:

[
  { "private_ip": "ip1", "public_dns_name": "dns1" },
  { ... },
  { ... }, 
  { ... }
]

La variable 'serveurs' enregistrée ressemble à ceci:

"servers": {
    "changed": true,
    "msg": "All items completed",
    "results": [
        {
            ...
            "tagged_instances": [
                {
                    ...
                    "private_ip": "ip1",
                    "public_dns_name": "dns1",
                    ...
                },
                {
                    ...
                    "private_ip": "ip2",
                    "public_dns_name": "dns2",
                    ...
                }
            ]
        },
        {
            ...
            "tagged_instances": [
                {
                    ...
                    "private_ip": "ip3",
                    "public_dns_name": "dn3",
                    ...
                },
                {
                    ...
                    "private_ip": "ip4",
                    "public_dns_name": "dns4",
                    ...
                }
            ]
        },
        ...
    ]
}

Remarque: j'ai une solution assez moche en utilisant 'with_flattened' et une instruction de débogage pour créer une nouvelle variable enregistrée 'flattened_servers' que je mappe ensuite à nouveau. Mais j'espère une solution plus élégante :)

15
TomDotTom

Vous pouvez faire la compréhension de liste pour le convertir en liste de dict.

Par exemple: 

- name: Convert
  Shell: python -c "print [x for b in {{ servers }}['servers']['results'] for x in b['tagged_instances']]"
  register: my_list_of_dicts

En supposant que cette variable {{ servers }} contienne le dictionnaire entier (pas json).

2
Vor

Jinja2 est livré avec un filtre intégré sum qui peut être utilisé comme:

{{ servers.results | sum(attribute='tagged_instances', start=[]) }}
39
PChambino

Je voulais juste énumérer la solution de contournement "laide" car le code python ne fonctionnait pas pour moi

  - debug: var=item
    with_flattened:
      - "{{ servers.results|map(attribute='tagged_instances')|list }}"
    register: servers_instances_tmp
    no_log: True

  - set_fact: servers_instances="{{ servers_instances_tmp.results|map(attribute='item')|list }}"

  - debug: var=servers_instances
0
gadelkareem