Issue looping on block module for a set of tasks in Ansible
TL;DR
'with_items' is not a valid attribute for a Block
The error message says it all: you cannot loop over a block.
If you need to loop over a set of tasks, put them in a separate file and use include_tasks
Implementation (and some good practice...)
Below is an implementation based on your example illustrating the solution.
Since your question and code lacks some precision and since I pointed out some bad practices, please note that:
- I fixed the looped code to effectively use the
filenames
you loop on (I inferred it was supposed to thedeploy.db
file). Note the use ofloop_control
to disambiguate the variable name in the included file (i.e.db_filename
). - I made the code idempotent as much as possible by using the ansible module
copy
in place ofshell
and dropped thetouch
phase. - I transformed the var names to all lowercase and underscore separator.
- To make sure the copy task works on all occasion, I replaced the removed tasks with a single making sure the
basepath
dir exists. - I added a
unique
filter afterfilenames.split(',')
as well as atrim
filter on each value to remove possible duplicates and eventual spaces added by error in the coma separated list. - I used
not
keyword andbool
filter (for extra security) rather than a bare compare to a booleanFalse
value.
Here is the included file create_db_each.yml
---
- name: Check if file exists
stat:
path: "{{ basepath }}/{{ db_filename }}"
register: currdb
- name: Create the file with "done" line if not present
copy:
content: "done"
dest: "{{ basepath }}/{{ db_filename }}"
when: not currdb.stat.exists | bool
used in the following create_db.yml
playbook
---
- name: "Create my dbs"
hosts: localhost
gather_facts: false
tasks:
- name: Make sure the base directory exists
file:
path: "{{ basepath }}"
state: directory
- name: load each db
include_tasks: "create_db_each.yml"
when: layer == 'APP'
loop: "{{ filenames.split(',') | unique | map('trim') }}"
loop_control:
loop_var: db_filename
which gives
notes:
- first run only, run it again on your side to witness it reports
OK
everywhere - see the
filenames
parameter value to illustrate the use ofunique
andtrim
$ ansible-playbook -e basepath=/tmp/my/base/path -e "filenames='a.bla, b.toto, c , z.txt,a.bla'" -e layer=APP create_db.yml
PLAY [Create my dbs] ************************************************
TASK [Make sure the base directory exists] **************************
changed: [localhost]
TASK [load each db] *************************************************
included: /home/olcla/Sources/ZZ_tests/ansitests/create_db_each.yml for localhost => (item=a.bla)
included: /home/olcla/Sources/ZZ_tests/ansitests/create_db_each.yml for localhost => (item=b.toto)
included: /home/olcla/Sources/ZZ_tests/ansitests/create_db_each.yml for localhost => (item=c)
included: /home/olcla/Sources/ZZ_tests/ansitests/create_db_each.yml for localhost => (item=z.txt)
TASK [Check if file exists] *****************************************
ok: [localhost]
TASK [Create the file with "done" line if not present] **************
changed: [localhost]
TASK [Check if file exists] *****************************************
ok: [localhost]
TASK [Create the file with "done" line if not present] **************
changed: [localhost]
TASK [Check if file exists] *****************************************
ok: [localhost]
TASK [Create the file with "done" line if not present] **************
changed: [localhost]
TASK [Check if file exists] *****************************************
ok: [localhost]
TASK [Create the file with "done" line if not present] **************
changed: [localhost]
PLAY RECAP **********************************************************
localhost: ok=13 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ tree /tmp/my/base/path/
/tmp/my/base/path/
├── a.bla
├── b.toto
├── c
└── z.txt
$ for f in /tmp/my/base/path/*; do cat $f; echo; done
done
done
done
done
Ashar
Updated on July 05, 2022Comments
-
Ashar almost 2 years
I need to check if deploy.db file exists. If it does not exist, then I need to perform a set of tasks for which I'm using block.
Below is how i run the playbook
ansible-playbook test.yml -e Layer=APP -e BASEPATH="/logs" -e Filenames="file1,file2,file3"
Below is my complete playbook:
--- - name: "Play 1" hosts: localhost gather_facts: false tasks: - name: Construct debug: msg: "Run" - block: - stat: path="{{ BASEPATH }}/deploy.db" register: currdb - file: path="{{ BASEPATH }}/deploy.db" state=touch recurse=no when: currdb.stat.exists == False - shell: "echo done>>{{ BASEPATH }}/deploy.db" when: currdb.stat.exists == False when: Layer == 'APP' with_items: - "{{ Filenames.split(',') }}"
I'm getting the below error running the playbook:
ERROR! 'with_items' is not a valid attribute for a Block The error appears to be in '/app/test.yml': line 9, column 6, but may be elsewhere in the file depending on the exact syntax problem. The offending line appears to be: - block: ^ here
After researching a bit, I understand that neither with_items nor loop is supported by block module and the solution is to include task file.
I'm however, not sure how to get that to work. Can you please suggest what tweaks I need to inorder for my playbook to work ?
Considering i m on the latest version of Ansible are there other solutions.