Перебор вложенного списка/словаря с использованием шаблонов Jinja2

Я пытаюсь динамически настроить несколько серверов NFS в своей системе, создав их файлы /etc/exports с помощью Ansible. Я надеюсь, что смогу сделать это с помощью шаблона jinja2. Это шаблон jinja2, который я не могу понять, судя по моему списку экспорта.

В моей роли nfs определены следующие переменные:

      site_nfs_servers: ['ansibletarget1', 'ansibletarget2']

exports:
  - server: "ansibletarget1"
    shares:
      - path: "/my/first/share/path"
        client: "*"
        options: "rw,sync"
      - path: "/my/second/share/path"
        client: "*"
        options: "rw,sync,root_squash"
  - server: "ansibletarget2"
    shares:
      - path: "/another/shared/path/different/server"
        client: "*"
        options: "ro,sync"

Затем у меня есть следующая игра для создания шаблона:

      - name: Generate the exports file.
  template:
    src: exports.j2
    dest: /etc/exports
    owner: root
    group: root
    mode: '0750'

Мой шаблон на данный момент выглядит так:

      {% for export in exports %}
{% if ansible_hostname in export.server %}
{% for share in shares %}
{{ share.path }} {{ share.client }} {{ share.options }}
{% endfor %}
{% endif %}
{% endfor %}

Я не думаю, что я близок к созданию правильной структуры шаблона. Как, черт возьми, можно перебирать этот список?

2 ответа

Вам не хватает ссылки наexportв вашем втором цикле.

      {% for export in exports %}
{% if ansible_hostname in export.server %}
{% for share in export.shares %}
{{ share.path }} {{ share.client }} {{ share.options }}
{% endfor %}
{% endif %}
{% endfor %}

Однако было бы лучше определить доли в переменных хоста, как показано в ответе Владимира.

Создать инвентарь

      shell> cat hosts
[site_nfs_servers]
ansibletarget1
ansibletarget2

и поместите общие ресурсы в хост_vars

      shell> cat host_vars/ansibletarget1.yml 
shares:
  - path: "/my/first/share/path"
    client: "*"
    options: "rw,sync"
  - path: "/my/second/share/path"
    client: "*"
    options: "rw,sync,root_squash"
      shell> cat host_vars/ansibletarget2.yml 
shares:
  - path: "/another/shared/path/different/server"
    client: "*"
    options: "ro,sync"

Создайте упрощенную роль для тестирования

      shell> tree roles/my_nfs_role/
roles/my_nfs_role/
├── tasks
│   └── main.yml
└── templates
    └── exports.j2

2 directories, 2 files
      shell> cat roles/my_nfs_role/tasks/main.yml 
- template:
    src: exports.j2
    dest: /etc/exports.test
      shell> cat roles/my_nfs_role/templates/exports.j2 
{% for share in shares %}
{{ share.path }} {{ share.client }} {{ share.options }}
{% endfor %}

Затем используйте группу инвентаря и роль в сборнике сценариев.

      shell> cat playbook.yml
- hosts: site_nfs_servers
  roles:
    - my_nfs_role

Запустите playbook и создайте файлы

      shell> ansible-playbook -i hosts playbook.yml

PLAY [site_nfs_servers] ************************************************

TASK [my_nfs_role : template] ******************************************
changed: [ansibletarget1]
changed: [ansibletarget2]
 ...
      shell> ssh admin@ansibletarget1 cat /etc/exports.test
/my/first/share/path * rw,sync
/my/second/share/path * rw,sync,root_squash

shell> ssh admin@ansibletarget2 cat /etc/exports.test
/another/shared/path/different/server * ro,sync

См. Пример настройки Ansible .


Если вы хотите сохранить общие ресурсы в одном объекте, поместите список в groups_vars. Чтобы упростить код, преобразуйте список в словарь. Например, вы можете использовать Community.general.groupby_as_dict

      shell> cat group_vars/all.yml
exports:
  - server: "ansibletarget1"
    shares:
      - path: "/my/first/share/path"
        client: "*"
        options: "rw,sync"
      - path: "/my/second/share/path"
        client: "*"
        options: "rw,sync,root_squash"
  - server: "ansibletarget2"
    shares:
      - path: "/another/shared/path/different/server"
        client: "*"
        options: "ro,sync"

exports_dict: "{{ exports|community.general.groupby_as_dict('server') }}"

дает

        exports_dict:
    ansibletarget1:
      server: ansibletarget1
      shares:
      - client: '*'
        options: rw,sync
        path: /my/first/share/path
      - client: '*'
        options: rw,sync,root_squash
        path: /my/second/share/path
    ansibletarget2:
      server: ansibletarget2
      shares:
      - client: '*'
        options: ro,sync
        path: /another/shared/path/different/server

Затем измените шаблон. Это должно создать те же файлы, что и раньше.

      shell> cat roles/my_nfs_role/templates/exports.j2 
{% for share in exports_dict[inventory_hostname]['shares'] %}
{{ share.path }} {{ share.client }} {{ share.options }}
{% endfor %}
Другие вопросы по тегам