Ansible

來自 JSON 格式的 Ansible jinja2 模板作為額外變數提供

  • October 7, 2021

我有這個 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 -%}

一個帶有 yaml 文件vhosts.ym l 的 ansible 角色,其中包含如下定義:

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

這工作正常,它將從模板在遠端伺服器上創建一個 nginx vhost 配置文件,如 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 中的內容作為單個條目的額外變數傳遞。有什麼辦法可以使它起作用嗎?

也許有更好的方法嗎?

您正在傳遞一個對象/字典,但您的程式碼需要一個列表。您需要在傳入時將其包裝在列表中,或者在使用時考慮不同的可能結構。

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

引用自:https://serverfault.com/questions/1079813