Шаблон 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