Hello. I have a problem with looping in Ansible. The solution is probably simple. I just lack the knowledge and need some help.
Context.
We have a JIRA URL. It has a project DDI. My task at first was to download all attachments from a JIRA issue like this one. It is called “Refresh MO2 DDI” and its unique ID is KAN-63.
Here is the Ansible playbook that does the download just fine:
---
- name: Get all task metadata for the DCR project
hosts: localhost
connection: local
gather_facts: true
vars_files:
- vars/main.yml
tasks:
- name: Set fact for Ansible date_time | dcr_jira {{ ansible_date_time.iso8601 }}
delegate_to: localhost
run_once: true
set_fact:
currentdate: "{{ ansible_date_time.date }}"
tags: linux
- name: Display Ansible date fact | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.debug:
var: currentdate
run_once: true
tags: linux
- name: Set Ansible current time fact | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.set_fact:
current_time: "{{ now(fmt='%Y-%m-%d_%H-%M-%S') }}"
run_once: true
tags: linux
###############DOWNLOAD SECTION############################
- name: Fetch Jira issue metadata | dcr_jira {{ ansible_date_time.iso8601 }}
community.general.jira:
uri: "{{ jira_url }}"
username: "{{ jira_user }}"
password: "{{ jira_api_token }}"
operation: fetch
# issue: "{{ issue_key }}"
issue: KAN-83
register: issue_data
delegate_to: localhost
# - name: Display DDI Refresh task unique Key
# ansible.builtin.debug:
# var: issue_data
####################CODITIONALS DEBUG###################################
- name: Set fact for task unique key | dcr_jira {{ ansible_date_time.iso8601 }}
delegate_to: localhost
run_once: true
set_fact:
task_unique_key: "{{ issue_data.meta.key }}"
tags: linux
- name: Display DCR task unique Key | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.debug:
var: "{{ task_unique_key }}"
- name: Display DCR Status | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.debug:
var: issue_data.meta.fields.status.name
- name: Display DCR Assignee | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.debug:
var: issue_data.meta.fields.assignee.displayName
- name: Display DCR Due Date | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.debug:
var: issue_data.meta.fields.duedate
- name: Announce Task launch if DCR Status is in Implementation, Assigned to Automation and Due Date is today | dcr_jira {{ ansible_date_time.iso8601 }}
debug:
msg: "DCR Status has changed to 'In Progress', the Task is now assigned to 'Automation API' and Due Date is today. Proceeding with DCR tasks automation at {{ ansible_date_time.iso8601 }}."
when: >
"In Progress" in issue_data.meta.fields.status.name and
"Automation API" in issue_data.meta.fields.assignee.displayName and
"{{ now(fmt='%Y-%m-%d') }}" in issue_data.meta.fields.duedate
####################END OF CONDITIONALS DEBUG###########################
- name: Run the DCR refresh conditional block to only execute when the conditions are met | dcr_jira {{ ansible_date_time.iso8601 }}
block:
# - name: Truncate the Ansible log
# ansible.builtin.shell:
# cmd: "truncate --s 0 /var/log/ansible/hosts/localhost"
- name: Download DCR SQL scripts to the server | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.get_url:
url: "{{ item.content }}"
dest: "{{ scratchpad_dcr_runtime }}/{{ item.filename }}"
url_username: "{{ jira_user }}"
url_password: "{{ jira_api_token }}"
force_basic_auth: yes
mode: '0644'
loop: "{{ issue_data.meta.fields.attachment }}"
when: issue_data.meta.fields.attachment is defined
register: download_results
- name: Display downloaded SQL scripts | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.debug:
msg: "Downloaded: {{ item.dest }}"
loop: "{{ download_results.results }}"
when: item.changed
Here is the output:
[misoracle@ehsmg-mis-dba1 ansible]$ ap dcr.yml
[WARNING]: Found both group and host with same name: localhost
[WARNING]: Collection community.general does not support Ansible version 2.16.3
PLAY [Get all task metadata for the DCR project] ********************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************************************************
ok: [localhost]
TASK [Set fact for Ansible date_time | dcr_jira 2026-05-05T14:51:25Z] ***********************************************************************************************************************************
ok: [localhost]
TASK [Display Ansible date fact | dcr_jira 2026-05-05T14:51:25Z] ****************************************************************************************************************************************
ok: [localhost] => {
"currentdate": "2026-05-05"
}
TASK [Set Ansible current time fact | dcr_jira 2026-05-05T14:51:25Z] ************************************************************************************************************************************
ok: [localhost]
TASK [Fetch Jira issue metadata | dcr_jira 2026-05-05T14:51:25Z] ****************************************************************************************************************************************
ok: [localhost]
TASK [Set fact for task unique key | dcr_jira 2026-05-05T14:51:25Z] *************************************************************************************************************************************
ok: [localhost]
TASK [Display DCR task unique Key | dcr_jira 2026-05-05T14:51:25Z] **************************************************************************************************************************************
ok: [localhost] => {
"KAN-83": "{{KAN-83}}"
}
TASK [Display DCR Status | dcr_jira 2026-05-05T14:51:25Z] ***********************************************************************************************************************************************
ok: [localhost] => {
"issue_data.meta.fields.status.name": "In Progress"
}
TASK [Display DCR Assignee | dcr_jira 2026-05-05T14:51:25Z] *********************************************************************************************************************************************
ok: [localhost] => {
"issue_data.meta.fields.assignee.displayName": "Automation API"
}
TASK [Display DCR Due Date | dcr_jira 2026-05-05T14:51:25Z] *********************************************************************************************************************************************
ok: [localhost] => {
"issue_data.meta.fields.duedate": "2026-05-04"
}
TASK [Announce Task launch if DCR Status is in Implementation, Assigned to Automation and Due Date is today | dcr_jira 2026-05-05T14:51:25Z] ************************************************************
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: "In Progress" in issue_data.meta.fields.status.name and "Automation API" in
issue_data.meta.fields.assignee.displayName and "{{ now(fmt='%Y-%m-%d') }}" in issue_data.meta.fields.duedate
skipping: [localhost]
TASK [Download DCR SQL scripts to the server | dcr_jira 2026-05-05T14:51:25Z] ***************************************************************************************************************************
changed: [localhost] => (item={'self': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/attachment/10839', 'id': '10839', 'filename': 'DCR_020.sql', 'author': {'self': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/user?accountId=712020%3A7d15570a-3512-4d4d-8c3d-85e6359b582c', 'accountId': '712020:7d15570a-3512-4d4d-8c3d-85e6359b582c', 'emailAddress': 'clerambeau370@gmail.com', 'avatarUrls': {'48x48': 'https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7d15570a-3512-4d4d-8c3d-85e6359b582c/486224f3-f8a3-483f-b14c-acb285a53f79/48', '24x24': 'https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7d15570a-3512-4d4d-8c3d-85e6359b582c/486224f3-f8a3-483f-b14c-acb285a53f79/24', '16x16': 'https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7d15570a-3512-4d4d-8c3d-85e6359b582c/486224f3-f8a3-483f-b14c-acb285a53f79/16', '32x32': 'https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7d15570a-3512-4d4d-8c3d-85e6359b582c/486224f3-f8a3-483f-b14c-acb285a53f79/32'}, 'displayName': 'clerambeau', 'active': True, 'timeZone': 'US/Eastern', 'accountType': 'atlassian'}, 'created': '2026-05-04T18:48:05.045-0400', 'size': 59, 'mimeType': 'text/plain', 'content': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/attachment/content/10839', 'thumbnail': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/attachment/thumbnail/10839'})
TASK [Display downloaded SQL scripts | dcr_jira 2026-05-05T14:51:25Z] ***********************************************************************************************************************************
ok: [localhost] => (item={'msg': 'OK (59 bytes)', 'status_code': 200, 'changed': True, 'checksum_dest': None, 'checksum_src': '1d6f17974f8fac35730491dedd15469be2f9dd41', 'dest': '/mnt/dba/automation/dcr/runtime/DCR_020.sql', 'elapsed': 0, 'url': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/attachment/content/10839', 'src': '/home/misoracle/.ansible/tmp/ansible-tmp-1777992686.9735906-2926797-247724442560080/tmp7jl0sry0', 'md5sum': '268eb495f2fda3b4247c21a3b59a1632', 'uid': 55561, 'gid': 55561, 'owner': 'misoracle', 'group': 'misoracle', 'mode': '0644', 'state': 'file', 'size': 59, 'invocation': {'module_args': {'url': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/attachment/content/10839', 'dest': '/mnt/dba/automation/dcr/runtime/DCR_020.sql', 'url_username': 'clerambeau370@gmail.com', 'url_password': 'VALUE_SPECIFIED_IN_NO_LOG_PARAMETER', 'force_basic_auth': True, 'mode': '0644', 'force': False, 'http_agent': 'ansible-httpget', 'use_proxy': True, 'validate_certs': True, 'use_gssapi': False, 'backup': False, 'checksum': '', 'timeout': 10, 'unredirected_headers': [], 'decompress': True, 'use_netrc': True, 'unsafe_writes': False, 'client_cert': None, 'client_key': None, 'headers': None, 'tmp_dest': None, 'ciphers': None, 'owner': None, 'group': None, 'seuser': None, 'serole': None, 'selevel': None, 'setype': None, 'attributes': None}}, 'failed': False, 'item': {'self': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/attachment/10839', 'id': '10839', 'filename': 'DCR_020.sql', 'author': {'self': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/user?accountId=712020%3A7d15570a-3512-4d4d-8c3d-85e6359b582c', 'accountId': '712020:7d15570a-3512-4d4d-8c3d-85e6359b582c', 'emailAddress': 'clerambeau370@gmail.com', 'avatarUrls': {'48x48': 'https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7d15570a-3512-4d4d-8c3d-85e6359b582c/486224f3-f8a3-483f-b14c-acb285a53f79/48', '24x24': 'https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7d15570a-3512-4d4d-8c3d-85e6359b582c/486224f3-f8a3-483f-b14c-acb285a53f79/24', '16x16': 'https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7d15570a-3512-4d4d-8c3d-85e6359b582c/486224f3-f8a3-483f-b14c-acb285a53f79/16', '32x32': 'https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7d15570a-3512-4d4d-8c3d-85e6359b582c/486224f3-f8a3-483f-b14c-acb285a53f79/32'}, 'displayName': 'clerambeau', 'active': True, 'timeZone': 'US/Eastern', 'accountType': 'atlassian'}, 'created': '2026-05-04T18:48:05.045-0400', 'size': 59, 'mimeType': 'text/plain', 'content': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/attachment/content/10839', 'thumbnail': 'https://clerambeau370-1776214257398.atlassian.net/rest/api/2/attachment/thumbnail/10839'}, 'ansible_loop_var': 'item'}) => {}
MSG:
Downloaded: /mnt/dba/automation/dcr/runtime/DCR_020.sql
PLAY RECAP **********************************************************************************************************************************************************************************************
localhost : ok=12 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
[misoracle@ehsmg-mis-dba1 ansible]$
However, as you can see in the playbook above, the issue ID is hardcoded:
issue: KAN-83
the problem is that there will be MANY different issues with other IDs which we do not know in advance. So what I need is to change the playbook above to connect to JIRA, query it for all issues under the project DDI.
Here is a view of such dashboard. As you can see there are three issues instead of one now: KAN-63, KAN-82, KAN-83.
I have gone as far as being able to get the issue IDs debugged and specific directories created for each issue in another playbook.
---
- name: Get all task metadata for the DCR project
hosts: localhost
connection: local
gather_facts: true
vars_files:
- vars/main.yml
tasks:
- name: Set fact for Ansible date_time | dcr_jira {{ ansible_date_time.iso8601 }}
delegate_to: localhost
run_once: true
set_fact:
currentdate: "{{ ansible_date_time.date }}"
tags: linux
- name: Display Ansible date fact | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.debug:
var: currentdate
run_once: true
tags: linux
- name: Set Ansible current time fact | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.set_fact:
current_time: "{{ now(fmt='%Y-%m-%d_%H-%M-%S') }}"
run_once: true
tags: linux
- name: Display the formatted time | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.debug:
var: current_time
###############DOWNLOAD SECTION############################
- name: Search for all issues in project {{ project_key }}
community.general.jira:
uri: "{{ jira_url }}"
username: "{{ jira_user }}"
password: "{{ jira_api_token }}"
# Use cloud=true if using Jira Cloud
cloud: true
operation: search
jql: "project = {{ project }}"
# Set maxresults to high enough number to catch all tasks
maxresults: 100
register: pr01_issues
- name: Display details of each JIRA task
ansible.builtin.debug:
msg: "Key: {{ item.key }}, Summary: {{ item.fields.summary }}, Status: {{ item.fields.status.name }}"
loop: "{{ pr01_issues.meta.issues }}"
# Only print essential information
loop_control:
label: "{{ item.key }}"
###########################################################
- name: Create a directory with specific permissions
ansible.builtin.file:
path: "{{ scratchpad_dcr_runtime }}/{{ item.key }}"
state: directory
mode: '0755'
loop: "{{ pr01_issues.meta.issues }}"
loop_control:
label: "{{ item.key }}"
Output:
[misoracle@ehsmg-mis-dba1 ansible]$ ap dcr_jira01.yml
[WARNING]: Found both group and host with same name: localhost
[WARNING]: Collection community.general does not support Ansible version 2.16.3
PLAY [Get all task metadata for the DCR project] ***********************************************************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Set fact for Ansible date_time | dcr_jira 2026-05-05T14:43:02Z] **************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Display Ansible date fact | dcr_jira 2026-05-05T14:43:02Z] *******************************************************************************************************************************************************************************************
ok: [localhost] => {
"currentdate": "2026-05-05"
}
TASK [Set Ansible current time fact | dcr_jira 2026-05-05T14:43:02Z] ***************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Display the formatted time | dcr_jira 2026-05-05T14:43:02Z] ******************************************************************************************************************************************************************************************
ok: [localhost] => {
"current_time": "2026-05-05_10-43-02"
}
TASK [Search for all issues in project {{ project_key }}] **************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Display details of each JIRA task] *******************************************************************************************************************************************************************************************************************
ok: [localhost] => (item=KAN-83) => {}
MSG:
Key: KAN-83, Summary: 26_ardddddf2345345, Status: In Progress
ok: [localhost] => (item=KAN-82) => {}
MSG:
Key: KAN-82, Summary: 26_artfgsdfsf2345345, Status: In Progress
ok: [localhost] => (item=KAN-63) => {}
MSG:
Key: KAN-63, Summary: Refresh MO2 DDI, Status: In Progress
TASK [Create a directory with specific permissions] ********************************************************************************************************************************************************************************************************
changed: [localhost] => (item=KAN-83)
changed: [localhost] => (item=KAN-82)
changed: [localhost] => (item=KAN-63)
PLAY RECAP *************************************************************************************************************************************************************************************************************************************************
localhost : ok=8 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[misoracle@ehsmg-mis-dba1 ansible]$
However, when it is time to actually DOWNLOAD all attachments belonging to each issue (like KAN-82 and others) into the newly created directories, I am at a loss. Whatever I try doesnt work.
- name: Download DCR SQL scripts to the server | dcr_jira {{ ansible_date_time.iso8601 }}
ansible.builtin.get_url:
url: "{{ item.content }}"
dest: "{{ scratchpad_dcr_runtime }}/{{ item.filename }}"
url_username: "{{ jira_user }}"
url_password: "{{ jira_api_token }}"
force_basic_auth: yes
mode: '0644'
loop: "{{ issue_data.results }}"
loop_control:
label: "{{ item.filename }}"
# when: item.filename.endswith('.sql')
register: download_results
TASK [Download DCR SQL scripts to the server | dcr_jira 2026-05-05T14:46:29Z] ******************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {}
MSG:
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'content'. 'dict object' has no attribute 'content'
The error appears to be in '/etc/ansible/dcr_jira04.yml': line 68, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Download DCR SQL scripts to the server | dcr_jira {{ ansible_date_time.iso8601 }}
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
PLAY RECAP *************************************************************************************************************************************************************************************************************************************************
localhost : ok=7 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Please help. This is something simple I am missing about the looping and the variable to pass to the ansible.builtin.get_url
Thank you.
Nestor Kandinsky-Clerambeau.




