Skip the whole loop in Ansible - loops

What should I do if I want to skip the whole loop in Ansible?
According to guidelines,
While combining when with with_items (see Loops), ... when statement is processed separately for each item.
Thereby while running the playbook like that
---
- hosts: all
vars:
skip_the_loop: true
tasks:
- command: echo "{{ item }}"
with_items: [1, 2, 3]
when: not skip_the_loop
I get
skipping: [localhost] => (item=1)
skipping: [localhost] => (item=2)
skipping: [localhost] => (item=3)
Whereas I don't want a condition to be checked every time.
Then I came up with the idea of using inline conditions
- hosts: all
vars:
skip_the_loop: true
tasks:
- command: echo "{{ item }}"
with_items: "{{ [1, 2, 3] if not skip_the_loop else [] }}"
It seems to solve my problem, but then I get nothing as output. And I want only one line saying:
skipping: Loop has been skipped

You should be able to make Ansible evaluate the condition just once with Ansible 2's blocks.
---
- hosts: all
vars:
skip_the_loop: true
tasks:
- block:
- command: echo "{{ item }}"
with_items: [1, 2, 3]
when: not skip_the_loop
This will still show skipped for every item and every host but, as udondan pointed out, if you want to suppress the output you can add:
display_skipped_hosts=True
to your ansible.cfg file.

This can be done easily using include along with condition:
hosts: all
vars:
skip_the_loop: true
tasks:
- include: loop
when: not skip_the_loop
Whereas somewhere in tasks/ there is a file called loop.yml:
- command: echo "{{ item }}"
with_items: [1, 2, 3]

Related

Preserve format of the file while printing in Ansible

Below is my playbook to print the file.
I used couple of approaches but the file is not printed as is i.e. the new line formatting is gone when ansible prints the file contents.
- name: List startup files
shell: cat /tmp/test.txt
register: readws
- debug:
msg: "/tmp/test.txt on {{ inventory_hostname }} is: {{ readws.stdout_lines }}"
- debug:
msg: "/tmp/test.txt on {{ inventory_hostname }} is: {{ lookup('file', '/tmp/test.txt') }}"
cat /tmp/test.txt
i
m
good
Expected Ansible output:
TASK [debug] *****************************************************************************************
ok: [localhost] => {
"msg": "/tmp/test.txt on localhost is:
i
m
good
"
}
Ansible output:
TASK [List startup files] ******************************************************************
changed: [localhost]
TASK [debug] *****************************************************************************************
ok: [localhost] => {
"msg": "/tmp/test.txt on localhost is: [u'i', u'm ', u'good']"
}
TASK [debug] *****************************************************************************************
ok: [localhost] => {
"msg": "/tmp/test.txt on localhost is: i\nm \ngood"
}
Can you please suggest ?
You cannot really get what you require (unless maybe if you change the output callback plugin...).
The closest you can get is by displaying a list of lines like in the following example:
- name: Show file content
vars:
my_file: /tmp/test.txt
msg_content: |-
{{ my-file }} on localhost is:
{{ lookup('file', my_file) }}
debug:
msg: "{{ msg_content.split('\n') }}"
This might help who might come looking for simpler way to display a file in ansible.
stdout_lines prints the file with reasonable formatting.
- name: display the file needed
shell: cat /tmp/test.txt
register: test_file
- debug:
var: test_file.stdout_lines

How do i loop over hosts identified by wildcards in Ansible

Below is my playbook that works fine.
---
- hosts: "PROD_SERVERS"
user: "{{USER}}"
tasks:
- name: Check if all hosts are reachable
fail:
msg: "Server is UNREACHABLE."
when: "hostvars[item].ansible_facts|list|length == 0"
with_items: "{{ groups.PROD_SERVERS }}"
However, can you help me with the syntax when the host is presented as wildcard i.e {{ENV}}_*?
---
- hosts: "{{ENV}}_*"
user: "{{USER}}"
tasks:
- name: Check if all hosts are reachable
fail:
msg: "Server is UNREACHABLE."
when: "hostvars[item].ansible_facts|list|length == 0"
with_items: "{{ groups.{{ENV}}_* }}" <------- Need help with this part of the code
There are special variables also called as "magic variables" to identify the hosts in the current play. They are:
ansible_play_hosts
ansible_play_batch
You can use one of these variables to loop with instead of the inventory group name.
Example with ansible_play_hosts:
- fail:
msg: "Server is UNREACHABLE."
when: hostvars[item].ansible_facts|list|length == 0
with_items: "{{ ansible_play_hosts }}"
Update:
Changed the example for Ansible version "2.4.x", the loop should be performed with with_items rather than loop. Quoting from official documentation
We added loop in Ansible 2.5. It is not yet a full replacement for with_<lookup>, but we recommend it for most use cases.
Note: For Ansible "2.9.16" and "2.10.2" loop works as well.

How to pass a register value into a include_role loop

I have an ansible playbook that is reading in a list of files, and setting a register for those values. I want to then pass the list of files into an include_role task. Below is my current code.
- name: Get list of files
command: "sh -c 'find playbooks/vars/files/*.yml'"
register: find_files
- include_vars:
file: "{{ item }}"
loop: "{{ find_files.stdout_lines }}"
register: result
- name: call role
include_role:
name: myRole
loop: "{{ result.results }}"
When the playbook runs, its finds two files in the directory; file1.yml and file2.yml. But when it runs through the include_role loop, its passes file1.yml twice and never passes file2.yml. Trying to determine how I can ensure file2.yml gets passed to the role as well.
I was able to find the correct my issue by constructing an array and then feeding it into include_role and using the find module instead of shell.
- name: Recursively find yml files
find:
paths: ~/vars
recurse: yes
register: find_files
- name: Construct file array
set_fact:
file_arr: "{{ file_arr|default([]) + [file.path] }}"
with_items: "{{ find_files.files }}"
loop_control:
loop_var: file
- name: Topic Management
include_role:
name: kafkaTopicManagement
vars:
kafkaFiles: "{{ item }}"
with_items: "{{ file_arr }}"
This now feeds the the files into include_role.

Error with Ansible include_tasks while adding dynamic hosts in nested loop

Below is the playbook with import_tasks get_hosts.yml for building dynamic hosts in a nested loop. However, I get syntax error running the playbook.
{{ item.split('\t')[0] }} will have ip addresses separated by commas , and then a string seperated by /t
---
- name: "Play 1"
hosts: localhost
tasks:
- name: "Search database"
command: > mysql --user=root --password=p#ssword deployment
--host=localhost -Ns -e "SELECT dest_ip,file_dets FROM deploy_dets"
register: command_result
- name: Add hosts
include_tasks: "{{ playbook_dir }}/gethosts.yml"
dest_ip: "{{ item.split('\t')[0] }}"
groups: dest_nodes
file_dets: "{{ item.split('\t')[1] }}"
ansible_host: localhost
ansible_connection: local
with_items: "{{ command_result.stdout_lines }}"
And below is my get_hosts.yml file
add_host:
name: "{{ item }}"
with_items: "{{ dest_ip.split(',') }}"
Output:
$ ansible-playbook testinclude.yml
ERROR! Syntax Error while loading YAML. did not find expected key
The error appears to be in '/app/deployment/testinclude.yml': line 23, column 8, but may be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
include_tasks: "{{ playbook_dir }}/gethosts.yml"
dest_ip: "{{ item.split('\t')[0] }}"
^ 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 }}"
Can you please suggest
Perhaps you forgot vars parameter, so:
include_tasks: "{{ playbook_dir }}/gethosts.yml"
vars: # <------------------------------------------- HERE
dest_ip: "{{ item.split('\t')[0] }}"
groups: dest_nodes

How to get the list of remote files under a Dir and iterate over to list out the contents via ansible

Does anyone knows how to get the list of remote files under a particular Dir and to iterate over them and list out the contents of each file via ansible?
For example , i have a location /var/spool/cron and it has many files which i need to cat <file> by iterate over each of them.
fileglob and lookup works locally.
Below is the play but not working as expected.
---
- name: Playbook to quick check the cron jobs for user
hosts: all
remote_user: root
gather_facts: False
tasks:
- name: cron state
shell: |
ls /var/spool/cron/
register: cron_status
- debug: var=item
with_items:
- "{{ cron_status.stdout_lines }}"
Try this as an example
---
- name: Playbook
hosts: all
become: root
gather_facts: False
tasks:
- name: run ls-
shell: |
ls -d1 /etc/cron.d/*
register: cron_status
- name: cat files
shell: cat {{ item }}
register: files_cat
with_items:
- "{{ cron_status.stdout_lines }}"
- debug: var=item
with_items:
- "{{ files_cat.results| map(attribute='stdout_lines')|list }}"
Just for the sake you someones Intrest..
Below Play will give you more cleaner stdout
---
- name: hostname
hosts: all
become: root
gather_facts: False
tasks:
- name: checking cron entries
shell: more /var/spool/cron/*
register: cron_status
- debug: var=cron_status.stdout_lines

Resources