Шаблон Ansible jinja2 из формата JSON, предоставляемый в виде дополнительных переменных.

У меня есть этот шаблон jinja2:

      # {{ ansible_managed }}

{% for vhost in nginx_vhosts %}
{%- if vhost.name == item.name -%}

# redirect www to non-www
server {
    listen {{ nginx_port }};
    listen [::]:{{ nginx_port }};
    port_in_redirect off;

    server_name www.{{ vhost.name }};
    return 301 http://{{ vhost.name }}$request_uri;
}
{%- endif -%}
{%- endfor -%}

Ansible-роль с yaml-файлом vhosts.ym l, содержащим такие определения:

      nginx_vhosts:
      - name: "test1.com"
        repo: "git1"
        branch: master
        state: present
      - name: "test2.com"
        repo: "git2"
        branch: master
        state: present
...
      - name: "test101.com"
        repo: "git101"
        branch: master
        state: present

Задача внутри playbook.yml :

      - name: "Generate nginx vhost configuration file"
  template:
    src: templates/nginx-vhost-template.j2
    dest: "{{ nginx_vhosts_dir }}/{{ item.name }}.conf"
    owner: "{{ nginx_user }}"
    group: "{{ nginx_group }}"
    mode: 0640
  with_items:
    - "{{ nginx_vhosts }}"
  when:
    - item.state == 'present'
  notify:
    - nginx-restart

Я запустил такс вроде:

      ansible-playbook -l web1 playbook.yml --tags=nginx-vhost-config

который работает нормально, он создаст из шаблона файл конфигурации nginxvhost на удаленном сервере как domain1.com.conf и так далее для всех найденных определений.

Предполагая, что в файле vhosts.yml у меня есть от test1.com до test100.com, я добавлю, скажем, test101.com и хочу запускать задачи строго для этого test101.com, а не для всех предыдущих хостов. Итак, я попробовал что-то вроде этого:

      ansible-playbook -l web1 playbook.yml --tags=nginx-vhost-config -e "{ 'nginx_vhosts': { 'name': 'test101.com', 'state': 'present', 'repo': 'git101', 'branch': 'master' }}"

Проблема в том, что это приводит к ошибке при попытке заменить значения из шаблона jinja2.

      An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.errors.AnsibleUndefinedVariable: 'ansible.parsing.yaml.objects.AnsibleUnicode object' has no attribute 'name'

Я также пробовал использовать цикл вместо with_items , но безуспешно.

Я понимаю, что при использовании дополнительных переменных содержимое предоставляется в формате JSON, но мне не удалось найти другой способ передать содержимое из vhosts.yml в виде дополнительных переменных для одной записи. Есть ли способ сделать это функциональным?

Может быть, есть лучший подход?

1 ответ

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

Сначала вам следует сократить количество мест, на которые ссылаютсяnginx_vhostsиспользуя текущий элемент цикла непосредственно в вашем шаблоне:

      # {{ ansible_managed }}

# redirect www to non-www
server {
    listen {{ nginx_port }};
    listen [::]:{{ nginx_port }};
    port_in_redirect off;

    server_name www.{{ item.name }};
    return 301 http://{{ item.name }}$request_uri;
}

Затем вы можете немного изменить передаваемую структуру:

      "{ 'nginx_vhosts': [{ 'name': 'test101.com', 'state': 'present', 'repo': 'git101', 'branch': 'master' }]}"

Или немного измените свой цикл:

      - name: "Generate nginx vhost configuration file"
  template:
    src: templates/nginx-vhost-template.j2
    dest: "{{ nginx_vhosts_dir }}/{{ item.name }}.conf"
    owner: "{{ nginx_user }}"
    group: "{{ nginx_group }}"
    mode: "0640"
  loop: "{{ [ nginx_vhosts ] | flatten }}"
  when:
    - item.state == 'present'
  notify:
    - nginx-restart
Другие вопросы по тегам