Ansible jinja2 模板以 JSON 格式提供,作为 extra-vars

Ansible jinja2 模板以 JSON 格式提供,作为 extra-vars

我有这个 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 文件的 ansible 角色虚拟主机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

里面有任务剧本.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但没有运气。

我理解,使用 extra-vars 时,提供的内容是 JSON 格式,但我找不到其他方法将 vhosts.yml 中的内容作为单个条目的 extra vars 传递。有什么方法可以实现此功能吗?

也许还有更好的方法吗?

答案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

相关内容