Ansible inline jinja templating out to a list - ansible
I can't figure out why this wouldn't work.
I'm using jinja to dynamically generate the list I would pass to the vmware_guest module, so I can decide in host or group vars if I would like to add additional disks.
I'm using the vmware_disk_info module to look up the size of the template disk and then add any additional disks that I would define in a group var.
It looks to me like the outputted list just isn't a list????
---
- name: "Get facts for named template"
vmware_guest_disk_info:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
datacenter: "{{ datacenter_name }}"
name: "{{ template_name }}"
register: template_disk
delegate_to: localhost
- name: "Define new disk structure"
set_fact:
vm_disks: >-
[{% for disk in (template_disk.guest_disk_info|dictsort) %}{
'size_kb': {{ disk[1].capacity_in_kb }},
'datastore': {{ datastore_name }}},
{% endfor %}
{% for disk in additional_disks|default([]) %}{
{% if disk.size_gb is defined %}'size_gb': {{ disk.size_gb }},{% endif %}
{% if disk.size_mb is defined %}'size_mb': {{ disk.size_mb }},{% endif %}
{% if disk.size_kb is defined %}'size_kb': {{ disk.size_kb }},{% endif %}
'datastore': {{ datastore_name }}},
{% endfor %}]
delegate_to: localhost
- name: Clone the template
vmware_guest:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
name: "{{ inventory_hostname }}"
template: "{{ template_name }}"
datacenter: "{{ datacenter_name }}"
folder: "/{{ datacenter_name }}/vm/{{ folder_name }}"
cluster: "{{ cluster_name }}"
datastore: "{{ datastore_name }}"
resource_pool: "{{ resource_pool_name }}"
disk: "{{ vm_disks }}"
hardware:
memory_gb: "{{ mem_size_gb }}"
num_cpu: "{{ cpu_size }}"
networks:
- name: "{{ network_name }}"
ip: "{{ ansible_host }}"
netmask: "{{ network_mask }}"
gateway: "{{ network_gw }}"
type: static
customization:
hostname: "{{ inventory_hostname }}"
domain: "{{ domain_name }}"
dns_suffix:
- "{{ domain_name }}"
dns_servers: "{{ network_dns }}"
state: poweredon
wait_for_ip_address: yes
delegate_to: localhost
and an example var would be:
additional_disks:
- size_gb: "120"
datastore: "VSAN_Datastore"
the error out:
fatal: [docker02 -> localhost]: FAILED! => changed=false
module_stderr: |-
Traceback (most recent call last):
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075176.0007603-201082838827202/AnsiballZ_vmware_guest.py", line 102, in <module>
_ansiballz_main()
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075176.0007603-201082838827202/AnsiballZ_vmware_guest.py", line 94, in _ansiballz_main
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075176.0007603-201082838827202/AnsiballZ_vmware_guest.py", line 40, in invoke_module
runpy.run_module(mod_name='ansible.modules.cloud.vmware.vmware_guest', init_globals=None, run_name='__main__', alter_sys=True)
File "/usr/lib/python3.6/runpy.py", line 205, in run_module
return _run_module_code(code, init_globals, run_name, mod_spec)
File "/usr/lib/python3.6/runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/tmp/ansible_vmware_guest_payload_fiddyn_z/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2834, in <module>
File "/tmp/ansible_vmware_guest_payload_fiddyn_z/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2823, in main
File "/tmp/ansible_vmware_guest_payload_fiddyn_z/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2342, in deploy_vm
File "/tmp/ansible_vmware_guest_payload_fiddyn_z/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2005, in configure_disks
AttributeError: 'str' object has no attribute 'get'
module_stdout: ''
msg: |-
MODULE FAILURE
See stdout/stderr for the exact error
rc: 1
The full traceback is:
Traceback (most recent call last):
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075175.423514-45894902001082/AnsiballZ_vmware_guest.py", line 102, in <module>
_ansiballz_main()
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075175.423514-45894902001082/AnsiballZ_vmware_guest.py", line 94, in _ansiballz_main
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075175.423514-45894902001082/AnsiballZ_vmware_guest.py", line 40, in invoke_module
runpy.run_module(mod_name='ansible.modules.cloud.vmware.vmware_guest', init_globals=None, run_name='__main__', alter_sys=True)
File "/usr/lib/python3.6/runpy.py", line 205, in run_module
return _run_module_code(code, init_globals, run_name, mod_spec)
File "/usr/lib/python3.6/runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/tmp/ansible_vmware_guest_payload_mspbq6yr/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2834, in <module>
File "/tmp/ansible_vmware_guest_payload_mspbq6yr/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2823, in main
File "/tmp/ansible_vmware_guest_payload_mspbq6yr/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2342, in deploy_vm
File "/tmp/ansible_vmware_guest_payload_mspbq6yr/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2005, in configure_disks
AttributeError: 'str' object has no attribute 'get'
example var output:
ok: [gluster01] =>
vm_disks: |-
[{
'size_kb': 125829120,
'datastore': VSAN_Datastore},
{
'size_gb': 120, 'datastore': VSAN_Datastore},
]
ok: [gluster02] =>
vm_disks: |-
[{
'size_kb': 125829120,
'datastore': VSAN_Datastore},
{
'size_gb': 120, 'datastore': VSAN_Datastore},
]
ok: [docker01] =>
vm_disks: |-
[{
'size_kb': 125829120,
'datastore': VSAN_Datastore},
]
New code based on below suggestion:
The same error, however:
- name: "Define new disk structure"
set_fact:
vm_disks: >-
{%- set results = [] -%}
{%- for osdisk in ( template_disk.guest_disk_info | dictsort ) -%}
{%- set od = { "size_kb": osdisk[1].capacity_in_kb } -%}
{%- set _ = od.update({ "datastore": osdisk[1].backing_datastore }) -%}
{%- set _ = results.append(od) -%}
{%- endfor -%}
{%- for disk in additional_disks|default([]) -%}
{%- set d = {"size_gb": disk.size_gb} if (disk.size_gb is defined) else {} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endfor -%}
"{{ results }}"
var debugging:
TASK [vm_clone : Debugging var] *******************************************************************************************************************
ok: [gluster01] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}, {''size_gb'': ''120'', ''datastore'': ''VSAN_Datastore''}]"'
ok: [gluster02] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}, {''size_gb'': ''120'', ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker01] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker02] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker03] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker04] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker05] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
This looks like a list to me, So to verify this, I piped the result to the to_json filter, and it errored out saying, it's not a str it's a list.
So it is definitely a list.
As Uttam correctly pointed out, but didn't provide an answer for, the problem is that your set_fact: produces a string but disks must be a list of dict, as one can see from the fine manual (and the code)
There are two reasons: the first is that ansible only auto-coerces JSON-looking strings into actual python list and dict structures, but you have used python syntax with the single quoted string literals and trailing commas, both of which are illegal is JSON
the second is that one should never build up a rich data structure in jinja using text: it has strong support for those data structures, as well as the wonderful | to_json and |from_json filters to ensure the output is legal JSON and correctly escaped characters
But I know that's a lot of words, so I believe the smallest change you can make to cause your situation to work is to stop using single quotes and guard the trailing comma:
- name: "Define new disk structure"
set_fact:
vm_disks: >-
[
{% for disk in (template_disk.guest_disk_info|dictsort) %}
{{ "" if loop.first else "," }}
{
"size_kb": {{ disk[1].capacity_in_kb }},
"datastore": "{{ datastore_name }}"
}
{% endfor %}
{% for disk in additional_disks|default([]) %}
{{ "," if template_disk.guest_disk_info else "" }}
{
{% if disk.size_gb is defined %}"size_gb": {{ disk.size_gb }},{% endif %}
{% if disk.size_mb is defined %}"size_mb": {{ disk.size_mb }},{% endif %}
{% if disk.size_kb is defined %}"size_kb": {{ disk.size_kb }},{% endif %}
"datastore": "{{ datastore_name }}"
}
{% endfor %}
]
The correct code would be something akin to:
set_fact:
vm_disks: >-
{%- set results = [] -%}
{%- for disk in additional_disks|default([]) -%}
{%- set d = {"datastore": datastore_name} -%}
{%- set _ = d.update({"size_gb": disk.size_gb} if (disk.size_gb is defined) else {}) -%}
{%- set _ = results.append(d) -%}
{%- endfor -%}
{{ results }}
final working code, Big Thanks to #mdaniel
- name: "Get facts for named template"
vmware_guest_disk_info:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
datacenter: "{{ datacenter_name }}"
name: "{{ template_name }}"
register: template_disk
delegate_to: localhost
- name: "Define new disk structure"
set_fact:
vm_disks: >-
{%- set results = [] -%}
{%- for osdisk in ( template_disk.guest_disk_info | dictsort ) -%}
{%- set od = { "size_kb": osdisk[1].capacity_in_kb } -%}
{%- set _ = od.update({ "datastore": osdisk[1].backing_datastore }) -%}
{%- set _ = results.append(od) -%}
{%- endfor -%}
{%- for disk in additional_disks|default([]) -%}
{%- if (disk.size_gb is defined) -%}
{%- set d = {"size_gb": disk.size_gb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- if (disk.size_mb is defined) -%}
{%- set d = {"size_mb": disk.size_mb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- if (disk.size_kb is defined) -%}
{%- set d = {"size_kb": disk.size_kb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- endfor -%}
{{ results }}
- name: Clone the template
vmware_guest:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
name: "{{ inventory_hostname }}"
template: "{{ template_name }}"
datacenter: "{{ datacenter_name }}"
folder: "/{{ datacenter_name }}/vm/{{ folder_name }}"
cluster: "{{ cluster_name }}"
datastore: "{{ datastore_name }}"
resource_pool: "{{ resource_pool_name }}"
disk: "{{ vm_disks }}"
hardware:
memory_gb: "{{ mem_size_gb }}"
num_cpu: "{{ cpu_size }}"
networks:
- name: "{{ network_name }}"
ip: "{{ ansible_host }}"
netmask: "{{ network_mask }}"
gateway: "{{ network_gw }}"
type: static
customization:
hostname: "{{ inventory_hostname }}"
domain: "{{ domain_name }}"
dns_suffix:
- "{{ domain_name }}"
dns_servers: "{{ network_dns }}"
state: poweredon
wait_for_ip_address: yes
delegate_to: localhost
and set your vars like this, in any combination you need:
additional_disks:
- size_gb: "120"
datastore_name: "VSAN_Datastore"
- size_mb: "10240"
datastore_name: "VSAN_Datastore"
- size_kb: "10240000"
datastore_name: "VSAN_Datastore"
Related
Ansible: how to get the calculated value of key "content" displayed into the playbook output
I am a beginner to ansible. How can I get the content of the csv file printed in my shell? I tryed to register the calculated value of content key and to display it via - ansible.builtin.debug: msg: "{{ csv_content }}" in another task, but I cannot see it into my playbook output. vars: current_date: "{{ '%Y-%m-%d' | strftime }}" tasks: - name: Dump results to /tmp/myfile.csv copy: dest: /tmp/mycsv_{{ '%Y-%m-%d' | strftime }}.csv content: | {% for host in hosts_list %} {% ---things--- %} {% set idm=host.inventory_hostname.split('_')[0].split('-')[1] %} {% set idm_padded = '%03d' % idm|int %} {% ---things--- %} {{ [idm_padded, --things-- ] | map('trim') | join(';') }} {% --things--- %} {% endfor %} vars: hosts_list: "{{ ansible_play_hosts | map('extract', hostvars) | list }}" register: csv_content run_once: yes - ansible.builtin.debug: msg: "{{ csv_content }}"
Rather than trying to get the content from the copy task, reverse your logic: render the content into a variable first, then use that variable as the argument to the content key in the copy task: - hosts: localhost gather_facts: false tasks: - set_fact: csv_content: | {% for host in hosts_list %} {% set idm=2 %} {% set idm_padded = '%03d' % idm|int %} {{ [idm_padded, "things" ] | map('trim') | join(';') }} {% endfor %} vars: hosts_list: - foo - bar - baz run_once: true - debug: msg: "{{ csv_content }}" - name: Dump results to /tmp/myfile.csv copy: dest: mycsv_{{ '%Y-%m-%d' | strftime }}.csv content: "{{ csv_content }}" run_once: true
Ansible : double loop into json file
I have as a source a json file that contains a list of blocks and data. from which i would like to extract information to create security rules, using a double loop in ansible. Below an example from my json file : [ { "Name":"Some_name", "NetworkFlow":[ { "GroupName":"Test1", "Type":"Ingress", "Env":"dev", "Server":[ "192.168.1.1", "192.168.1.2", ... ], "Service":[ { "Protocol":"TCP", "Port":"443" }, { "Protocol":"UDP", "Port":"21" }, .... ] }, .... ] } ] This is for a generic deployment, and for each "NetworkFlow" section, i have to loop in the list of servers and also in the list of protocols and ports to get a simular parsing like the below: #rule= Server,Protocol,Port,Type,Env,GroupName 192.168.1.1,TCP,443,Ingress,Dev,Test1 192.168.1.2,TCP,443,Ingress,Dev,Test1 192.168.1.1,UDP,21,Ingress,Dev,Test1 192.168.1.2,UDP,21,Ingress,Dev,Test1 I tried with_nested but it doesn't work, Any idea to deal with that please?
Create a file with the nested loop, for example shell> cat rules.yml - debug: msg: "{{ item.0 }},{{ item.1.Protocol }},{{ item.1.Port }},{{ outer_item.Type }},{{ outer_item.Env }},{{ outer_item.GroupName }}" with_nested: - "{{ outer_item.Server }}" - "{{ outer_item.Service }}" and include it - include_tasks: rules.yml loop: "{{ NetworkFlow }}" loop_control: loop_var: outer_item gives msg: 192.168.1.1,TCP,443,Ingress,dev,Test1 msg: 192.168.1.1,UDP,21,Ingress,dev,Test1 msg: 192.168.1.2,TCP,443,Ingress,dev,Test1 msg: 192.168.1.2,UDP,21,Ingress,dev,Test1 Q: "... have a list of ports separated by a comma and not just one port." A: Convert the data. For example shell> cat rules.yml - set_fact: Services: "{{ Services|from_yaml }}" vars: Services: | {% for service in oi.Service %} {% for port in service.Port.split(',') %} - Protocol: {{ service.Protocol }} Port: {{ port }} {% endfor %} {% endfor %} - debug: msg: "{{ i.0 }},{{ i.1.Protocol }},{{ i.1.Port }},{{ oi.Type }},{{ oi.Env }},{{ oi.GroupName }}" with_nested: - "{{ oi.Server }}" - "{{ Services }}" loop_control: loop_var: I gives msg: 192.168.1.1,TCP,443,Ingress,dev,Test1 msg: 192.168.1.1,TCP,22,Ingress,dev,Test1 msg: 192.168.1.1,TCP,53,Ingress,dev,Test1 msg: 192.168.1.1,UDP,21,Ingress,dev,Test1 msg: 192.168.1.2,TCP,443,Ingress,dev,Test1 msg: 192.168.1.2,TCP,22,Ingress,dev,Test1 msg: 192.168.1.2,TCP,53,Ingress,dev,Test1 msg: 192.168.1.2,UDP,21,Ingress,dev,Test1
set interface name in a variable with jinja loop on ansible
i want to set inside a variable interface name if is equals to a variable pass on command line so i'm using jinja like this : - name: Inizializzo la rete hosts: all gather_facts: true become: yes become_user: root tasks: - name: stampo interfacce set_fact: privata: "{% for interfacce in ansible_interfaces %} {% set int_tmp = 'ansible_facts.' ~ interfacce ~ '.macaddress' %} {% if {{int_tmp}}==mac_privata %} {{interfacce}} {% endif %} {% endfor %}" - name: Stampo debug: msg: "{{privata}}" but it doesn't works i call this : ansible-playbook test.yml --extra-vars "mac_privata=00:50:56:b7:bc:f1" i do this because i've more than three interface where i'm wrong? EDIT: #mdaniel Thanks for your answer but it seems that it doesn't substitute hostvars['ansible_' ~ interfacce ~ '.macaddress'] with content of ansible_ens32.macaddress. For example i do this : - name: Stampo debug: msg: "{{ ansible_ens32.macaddress }}" i've this output : TASK [Stampo] ********************************************************************************************************************************************** ok: [10.150.20.130] => { "msg": "00:50:56:b7:bb:f1" } but if i do this : - name: stampo interfacce set_fact: privata: >- {%- for interfacce in ansible_interfaces -%} {%- if interfacce != 'lo' -%} {%- set int_tmp = hostvars['ansible_' ~ interfacce ~ '.macaddress'] -%} {%- if int_tmp == mac_privata -%} {{ interfacce }} {%- endif -%} {%- endif -%} {%- endfor -%} - name: Stampo debug: msg: "{{privata}}" I'm expecting name of interface with mac_privata macaddress in privata variable if i do this : ansible-playbook test.yml --extra-vars "mac_privata=00:50:56:b7:bb:f1" i've ens_32 but it's empty: TASK [stampo interfacce] *********************************************************************************************************************************** task path: /mnt/c/Users/francesco.ferraro/ansible_test/test.yml:7 ok: [10.150.20.130] => { "ansible_facts": { "privata": "" }, "changed": false }
Any time one sees {{ inside another jinja2 context, it's almost certainly not what you what to happen. To dynamically look up a variable, use either vars[""] or hostvars[""], or if you prefer the lookup("vars", "") privata: >- {%- for interfacce in ansible_interfaces -%} {%- set int_tmp = vars['ansible_facts.' ~ interfacce ~ '.macaddress'] -%} {%- if int_tmp == mac_privata -%} {{ interfacce }} {%- endif -%} {%- endfor -%} Most cases support the conditional for loop, which can make the snippet a little shorter privata: >- {%- for interfacce in ansible_interfaces if mac_privata == vars['ansible_facts.' ~ interfacce ~ '.macaddress'] -%} {{ interfacce }} {%- endfor -%}
Creating a comma separated string from a dictionary in Ansible
I want to write an Ansible role to be able to alter a given Kafka topic. I am using a dictionary of key/value pairs. The command module is then used to execute a Kafka script that take a string of comma separated values. For instance, use app_kafka_topic list: --- app_kafka_topic: cleanup.policy : - "delete" retention.ms : - "146800000" partitions : - "6" replication-factor : - "2" and create the string: "cleanup.policy=delete,retention.ms=146800000,partitions=6,replication-factor=2" This is what I have so far. - name: Reading the Default Topic Properties set_fact: app_kafka_topic_properties_dicts: | {% set res = [] -%} {% for key in app_kafka_topic.keys() -%} {% for value in app_kafka_topic[key] -%} {% set ignored = res.extend([{'topic_property': key, 'value':value}]) -%} {%- endfor %} {%- endfor %} {{ res }} - name: Create Topic with Default Properties command: "{{ kafka_bin_dir }}/{{ kafka_config_script }} --zookeeper {{ prefix }}-kafka-{{ Kafka_node }}.{{ DNSDomain}}:{{ zookeeper_port }} --entity-type topics --alter --entity-name {{ kafka_topic }} --add-config {{ properties }}" with_items: "{{ app_kafka_topic_properties_dicts }}" register: createdTopic vars: properties: |- {% for key in app_kafka_topic.keys() %} {% for value in app_kafka_topic[key] %} "{{ key }}={{ value }}" {%- endfor %} {%- endfor %} However, the properties variable is not concatenating the values to the end of a string. Is there a way to append the values to a string and separate them by a comma?
Is this the code that you're looking for? play.yml - hosts: localhost gather_facts: no vars: string: "" app_kafka_topic: cleanup.policy : - "delete" retention_ms : - "146800000" partitions : - "6" replication_factor : - "2" tasks: - set_fact: string: "{{ string }}{{ (index > 0)|ternary(',','') }}{{ item.key }}={{ item.value[0] }}" loop: "{{ app_kafka_topic|dict2items }}" loop_control: index_var: index - debug: var: string $ ansible-playbook play.yml | grep string "string": "retention_ms=146800000,cleanup.policy=delete,replication_factor=2,partitions=6"
Vague deprecation error when running ansible playbook
My playbook contains vars that are passed to a role. When I run it, I get [DEPRECATION WARNING]: Skipping task due to undefined Error, in the future this will be a fatal error.. Here's what I have: --- - hosts: hadoopL0X become: yes become_method: sudo vars: logrotate_scripts: - name: "{{ item }}" with_items: - zookeeper - sa path: "/var/log{{ item }}/{{ item }}.log " options: - daily - rotate 3 - missingok - compress - notifempty roles: - log-rotation ... The role is as such: log-rotation/tasks/main.yml --- - name: Setup logrotate.d scripts template: src: logrotate.d.j2 dest: "{{ logrotate_conf_dir }}{{ item }}" with_items: "{{ logrotate_scripts }}" ... log-rotation/defaults/main.yml --- logrotate_conf_dir: "/etc/logrotate.d/" logrotate_scripts: [] ... log-rotation/templates/logrotate.d.j2 # {{ ansible_managed }} "{{ item.path }}" { {% if item.options is defined -%} {% for option in item.options -%} {{ option }} {% endfor -%} {% endif %} {%- if item.scripts is defined -%} {%- for name, script in item.scripts.iteritems() -%} {{ name }} {{ script }} endscript {% endfor -%} {% endif -%} } Any help would be much appreciated!
with_items can only be used with tasks, it cannot be used when defining variables, and because of that item isn't defined. It also looks like that the service variable isn't defined as well.