如何在 Ansible 中的剧本和角色之间循环



我尝试遍历geerlingguy.nginx Role来创建nginx VHosts。但我没有完成它:

Playbook.yml

- hosts: some.server
become: true
roles:
- geerlingguy.nginx
tasks:
- name: looping vhosts
include_tasks: vhosts.yml
loop:
- { name: 'vhost1.bla.com', state: 'present' }
- { name: 'vhost1.bla.com', state: 'present' }

对于此服务器,我创建了一个Host_vars文件:

host_vars.yml

nginx_worker_processes: "auto"
nginx_worker_connections: 768
nginx_extra_http_options: |
gzip on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
nginx_vhosts:
- listen: "443 ssl http2"
server_name: '{{ item.name }}'
server_name_redirect: " {{ item.name }} "
root: "/var/www/{{ item.name }}"
index: "index.php index.html index.htm"
access_log: "/var/www/{{ item.name }}/logs/access_{{ item.name }}.log"
error_log: "/var/www/{{ item.name }}/logs/erro_{{ item.name }}.log"
state: "{{ item.state }}"
template: "{{ nginx_vhost_template }}"
filename: "{{ item.name }}"
extra_parameters: |
ssl_certificate     /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_protocols       TLSv1.1 TLSv1.2;
ssl_ciphers         HIGH:!aNULL:!MD5;

这是来自geerlingguy.nginx Role的vhost.yml

- name: Remove default nginx vhost config file (if configured).
file:
path: "{{ nginx_default_vhost_path }}"
state: absent
when: nginx_remove_default_vhost | bool
notify: restart nginx
- name: Ensure nginx_vhost_path exists.
file:
path: "{{ nginx_vhost_path }}"
state: directory
mode: 0755
notify: reload nginx
- name: Add managed vhost config files.
template:
src: "{{ item.template|default(nginx_vhost_template) }}"
dest: "{{ nginx_vhost_path }}/{{ item.filename|default(item.server_name.split(' ')[0] ~ '.conf') }}"
force: true
owner: root
group: "{{ root_group }}"
mode: 0644
when: item.state|default('present') != 'absent'
with_items: "{{ nginx_vhosts }}"
notify: reload nginx
tags:
- skip_ansible_lint
- name: Remove managed vhost config files.
file:
path: "{{ nginx_vhost_path }}/{{ item.filename|default(item.server_name.split(' ')[0] ~ '.conf') }}"
state: absent
when: item.state|default('present') == 'absent'
with_items: "{{ nginx_vhosts }}"
notify: reload nginx
tags:
- skip_ansible_lint
- name: Remove legacy vhosts.conf file.
file:
path: "{{ nginx_vhost_path }}/vhosts.conf"
state: absent
notify: reload nginx

所以,当我运行剧本时,我得到了:

fatal: [some.server]: FAILED! => {
"msg": "[{'listen': '443 ssl http2', 'server_name': '{{ item.name }}'... HIGH:!aNULL:!MD5;\n'}]: 'item' is undefined

我以不同的方式尝试它,但总是得到相同的错误,如果有人可以帮助我,那就太好了。

你的方法不起作用,在这一点上你不会得到任何东西。此外,不可能定义变量或数据结构并在以后让 Jinja 逻辑对其进行评估。

geerlingguy 的实现提供了变量nginx_vhosts的定义。此变量必须是字典列表,然后自动处理此列表。

您有两个主要选项:

选项 1

您可以创建nginx_vhosts作为所有虚拟主机的字典列表。

nginx_vhosts:
- listen: "443 ssl http2"
server_name: "vhost1.bla.com"
server_name_redirect: "www.vhost1.bla.com"
root: "/var/www/vhost1.bla.com"
index: "index.php index.html index.htm"
error_page: ""
access_log: "/var/www/vhost1.bla.com/logs/access_vhost1.bla.com.log"
error_log: "/var/www/vhost1.bla.com/logs/error_vhost1.bla.com.log"
state: "present"
template: "{{ nginx_vhost_template }}"
filename: "vhost1.bla.com.conf"
extra_parameters: |
ssl_certificate     /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_protocols       TLSv1.1 TLSv1.2;
ssl_ciphers         HIGH:!aNULL:!MD5;
- listen: "443 ssl http2"
server_name: "vhost2.bla.com"
server_name_redirect: "www.vhost2.bla.com"
root: "/var/www/vhost2.bla.com"
index: "index.php index.html index.htm"
error_page: ""
access_log: "/var/www/vhost2.bla.com/logs/access_vhost2.bla.com.log"
error_log: "/var/www/vhost2.bla.com/logs/error_vhost2.bla.com.log"
state: "present"
template: "{{ nginx_vhost_template }}"
filename: "vhost2.bla.com.conf"
extra_parameters: |
ssl_certificate     /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_protocols       TLSv1.1 TLSv1.2;
ssl_ciphers         HIGH:!aNULL:!MD5;

选项 2

有点复杂,但我认为这是你的愿望,循环。

为包含以下内容的任务myvhost.yml创建单独的文件:

---
- name: create directories
file:
path: "{{ item }}"
state: directory
with_items:
- "/var/www/{{ vhost.name }}"
- "/var/www/{{ vhost.name }}/logs"
- name: define nginx_vhosts variable
set_fact:
nginx_vhosts:
- listen: "443 ssl http2"
server_name: '{{ vhost.name }}'
# server_name_redirect: " {{ vhost.name }} "
root: "/var/www/{{ vhost.name }}"
index: "index.php index.html index.htm"
access_log: "/var/www/{{ vhost.name }}/logs/access_{{ vhost.name }}.log"
error_log: "/var/www/{{ vhost.name }}/logs/erro_{{ vhost.name }}.log"
state: "{{ vhost.state }}"
# template: "{{ nginx_vhost_template }}"
filename: "{{ vhost.name }}"
extra_parameters: |
ssl_certificate     /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_protocols       TLSv1.1 TLSv1.2;
ssl_ciphers         HIGH:!aNULL:!MD5;
- name: include vhosts.yml from geerlingguy
include_role:
name: geerlingguy.nginx
tasks_from: vhosts

在这里,您可以使用新值设置变量nginx_vhosts,一个带有单个字典的列表。然后,从 geerlingguy 执行导入角色vhosts的任务。

另一方面,在剧本中,您可以使用循环导入新myvhost.yml

- name: looping vhosts
include_tasks: myvhost.yml
loop:
- { name: 'vhost1.bla.com', state: 'present' }
- { name: 'vhost2.bla.com', state: 'present' }
loop_control:
loop_var: vhost

变更说明

对于您的循环,您必须重命名循环变量,否则将与 geerlingguyvhosts.yml中的循环发生冲突(我在开始时忽略了这一点),请参阅loop_var: vhost。重命名循环变量后,当然还必须将myvhost.yml中的名称从item更改为vhost

在运行任务循环虚拟主机之前,geerlingguy.nginx角色应该运行一次,例如,如果它在剧本中列在roles:下。

我在myvhost.yml中所做的另一个更改.而不是include_tasks使用更好的include_roletasks_from: vhosts.

我现在注释掉了server_name_redirect:设置,因为它创建了导致nginx崩溃的nginx配置文件。如果您确实需要此设置,则必须更详细地分析此设置。

此外,在创建 VHosts 之前,证书文件(ssl-cert-snakeoil)必须存在。

完整的剧本可能如下所示:

---
- hosts: nginx
become: true
roles:
- geerlingguy.nginx
tasks:
- name: looping vhosts
include_tasks: myvhost.yml
loop:
- { name: 'vhost1.bla.com', state: 'present' }
- { name: 'vhost2.bla.com', state: 'present' }
loop_control:
loop_var: vhost

最新更新