Ansible jinja2 template from JSON format provided as extra-vars

Solution 1:

You are passing in an object/dictionary but your code is expecting a list. You need to either wrap it in a list when you pass it in, or account for the different possible structures when you consume it.

You should first reduce the number of places that reference nginx_vhosts by using the current loop item directly in your template:

# {{ 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;
}

You can then modify the structure you pass in slightly:

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

Or modify your loop slightly:

- 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