Abort further task execution, with multiple hosts - ansible

Using Ansible v2.9.12
Question: I'd like Ansible to fail/stop the play when a task fails, when multiple hosts execute the task. In that sense, Ansible should abort the task from further execution. The configuration should work in a role, so using serial, or using different plays, is not possible.
Example ;
- hosts:
- host1
- host2
- host3
any_errors_fatal: true
tasks:
- name: always fail
shell: /bin/false
throttle: 1
Provides ;
===== task | always fail =======
host1: fail
host2: fail
host3: fail
Meaning, the task is still executed on the second host and third host. I'd desire the whole play to fail/stop, once a task fails on a host. When the task fails on the last host, Ansible should abort as well.
Desired outcome ;
===== task | always fail =======
host1: fail
host2: not executed/skipped, cause host1 failed
host3: not executed/skipped, cause host1 failed
As you can see, I've fiddled around with error handling, but without prevail.
Background info: I've been developing an idempotent Ansible role for mysql. It is possible to setup a cluster with multiple hosts. The role also supports adding an arbiter.
The arbiter does not has the mysql application installed, but the host is still required in the play.
Now, imagine three hosts. Host1 is the arbiter, host2 and host3 have mysql installed, setup in a cluster. The applications are setup by the Ansible role.
Now, Ansible executes the role for a second/third/fourth/whatever time, and changes a config setting of mysql. Mysql needs a rolling restart. Usually, one writes some thing along the lines of:
- template:
src: mysql.j2
dest: /etc/mysql
register: mysql_config
when: mysql.role != 'arbiter'
- service:
name: mysql
state: restarted
throttle: 1
when:
- mysql_config.changed
- mysql.role != 'arbiter'
The downside of this Ansible configuration, is that if mysql fails to start on host2 due to whatever reason, Ansible will also restart mysql on host3. And that is undesired, because if mysql fails on host3 as well, then the cluster is lost. So, for this specific task I'd like Ansible to stop/abort/skip other tasks if mysql has failed to start on a single host in the play.

Ok, this works:
# note that test-multi-01 set host_which_is_skipped: true
---
- hosts:
- test-multi-01
- test-multi-02
- test-multi-03
tasks:
- set_fact:
host_which_is_skipped: "{{ inventory_hostname }}"
when: host_which_is_skipped
- shell: /bin/false
run_once: yes
delegate_to: "{{ item }}"
loop: "{{ ansible_play_hosts }}"
when:
- item != host_which_is_skipped
- result is undefined or result is not failed
register: result
- meta: end_play
when: result is failed
- debug:
msg: Will not happen
When the shell command is set to /bin/true, the command is executed on host2 and host3.

One way to solve this would be to run the playbook with serial: 1. That way, the tasks are executed serially on the hosts and as soon as one task fails, the playbook terminates:
- name: My playbook
hosts: all
serial: 1
any_errors_fatal: true
tasks:
- name: Always fail
shell: /bin/false
In this case, this results in the task only being executed on the first host. Note that there is also the order clause, with which you can also control the order in which hosts are run: https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html#hosts-and-users

Disclaimer: most of the credit of the fully working part of this answer is going to #Tomasz Klosinski's answer on Server Fault.
Here is for a partially working idea, that only falls short of one host.
For the demo, I purposely increased my hosts number to 5 hosts.
The idea is based on the special variables ansible_play_batch and ansible_play_hosts_all that are described in the above mentioned document page as:
ansible_play_hosts_all
List of all the hosts that were targeted by the play
ansible_play_batch
List of active hosts in the current play run limited by the serial, aka ‘batch’. Failed/Unreachable hosts are not considered ‘active’.
The idea, coupled with your trial at using throttle: 1 should work, but fail short of one host, executing on host2 when it should skip it.
Given the playbook:
- hosts: all
gather_facts: no
tasks:
- shell: /bin/false
when: "ansible_play_batch | length == ansible_play_hosts_all | length"
throttle: 1
This yields the recap:
PLAY [all] ***********************************************************************************************************
TASK [shell] *********************************************************************************************************
fatal: [host1]: FAILED! => {"changed": true, "cmd": "/bin/false", "delta": "0:00:00.003915", "end": "2020-09-06 22:09:16.550406", "msg": "non-zero return code", "rc": 1, "start": "2020-09-06 22:09:16.546491", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
fatal: [host2]: FAILED! => {"changed": true, "cmd": "/bin/false", "delta": "0:00:00.004736", "end": "2020-09-06 22:09:16.844296", "msg": "non-zero return code", "rc": 1, "start": "2020-09-06 22:09:16.839560", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
skipping: [host3]
skipping: [host4]
skipping: [host5]
PLAY RECAP ***********************************************************************************************************
host1 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
host2 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
host3 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
host4 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
host5 : ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Looking further on that, I landed on this answer of Server Fault, and this looks to be the right idea to craft your solution.
Instead of going the normal way, the idea is to delegate everything from the first host with a loop on all targeted hosts of the play, because, in a loop, you are then able to access the registered fact of the previous host in an easy manner, as long as your register it.
So here is the playbook:
- hosts: all
gather_facts: no
tasks:
- shell: /bin/false
loop: "{{ ansible_play_hosts }}"
register: failing_task
when: "failing_task | default({}) is not failed"
delegate_to: "{{ item }}"
run_once: true
This would yield the recap:
PLAY [all] ***********************************************************************************************************
TASK [shell] *********************************************************************************************************
failed: [host1 -> host1] (item=host1) => {"ansible_loop_var": "item", "changed": true, "cmd": "/bin/false", "delta": "0:00:00.003706", "end": "2020-09-06 22:18:23.822608", "item": "host1", "msg": "non-zero return code", "rc": 1, "start": "2020-09-06 22:18:23.818902", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
skipping: [host1] => (item=host2)
skipping: [host1] => (item=host3)
skipping: [host1] => (item=host4)
skipping: [host1] => (item=host5)
NO MORE HOSTS LEFT ***************************************************************************************************
PLAY RECAP ***********************************************************************************************************
host1 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
And just for the sake of proving it works as intended, altering it to make the host2 fail specifically, with the help of failed_when:
- hosts: all
gather_facts: no
tasks:
- shell: /bin/false
loop: "{{ ansible_play_hosts }}"
register: failing_task
when: "failing_task | default({}) is not failed"
delegate_to: "{{ item }}"
run_once: true
failed_when: "item == 'host2'"
Yields the recap:
PLAY [all] ***********************************************************************************************************
TASK [shell] *********************************************************************************************************
changed: [host1 -> host1] => (item=host1)
failed: [host1 -> host2] (item=host2) => {"ansible_loop_var": "item", "changed": true, "cmd": "/bin/false", "delta": "0:00:00.004226", "end": "2020-09-06 22:20:38.038546", "failed_when_result": true, "item": "host2", "msg": "non-zero return code", "rc": 1, "start": "2020-09-06 22:20:38.034320", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
skipping: [host1] => (item=host3)
skipping: [host1] => (item=host4)
skipping: [host1] => (item=host5)
NO MORE HOSTS LEFT ***************************************************************************************************
PLAY RECAP ***********************************************************************************************************
host1 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

Related

Ansible playbook is failing for 'become:yes'

The following ansible-playbook works fine for non-sudo access.
But fails when I un-comment become:yes
---
- hosts: all
become: yes
tasks:
- name: Register the policy file in a variable
read_csv:
path: policy.csv
delegate_to: localhost
register: csv_file
- name: Check rules pre-remediation
command: "{{ item.Compliance_check }}"
register: output
with_items:
"{{ csv_file.list }}"
- name: Perform remediation
command: "{{ item.item.Remediation }}"
when: item.item.Expected_result != item.stdout
with_items:
"{{ output.results }}"
The inventory file looks like:
10.136.59.110 ansible_ssh_user=username ansible_ssh_pass=password ansible_sudo_pass=password
Error I'm facing is:
user#hostname:~/git-repo/MCI$ ansible-playbook playbook.yaml -i inventory
PLAY [all] *******************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************
ok: [10.136.59.109]
TASK [Register the policy file in a variable] ********************************************************************************************
Sorry, try again.
fatal: [10.136.59.109 -> localhost]: FAILED! => {"changed": false, "module_stderr": "[sudo via ansible, key=mjcqjbcyeemygkxwycgeftiikivnylsj] password:\nsudo: no password was provided\nsudo: 1 incorrect password attempt\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}
PLAY RECAP *******************************************************************************************************************************
10.136.59.109 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Can't understand why this error is showing. I have tried providing correct sudo passwords in both inventory as well as at run-time using --ask-become-pass
Please help find out the cause of the error.

Select one usable server from inventory

I have a group of servers, which may or may not be available at the moment. I want to execute queries against a usable server. I don't know which one to use, though. So I thought I could use an include...until construct, but that doesn't work as expected.
Example:
main.yml
---
- hosts: localhost
tasks:
- include: get_available_node.yml
loop:
- localhost
- example.com
- localhost
loop_control:
loop_var: domain
until: available_domain is defined and available_domain|length > 0
- debug:
var: available_domain
get_available_node.yml
---
- get_url:
url: "http://{{ domain }}"
dest: /dev/null
register: url_attempt
ignore_errors: yes
- set_fact:
available_domain: "{{ domain }}"
when: url_attempt.failed == false
I thought, my loop should stop as soon as my available_domain var gets set. However, it doesn't.
PLAY [localhost] ******************************************************************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************************************
ok: [localhost]
TASK [include] ********************************************************************************************************************************************************************
included: /Volumes/Source Code/playground/stackoverflow/get_available_node.yml for localhost => (item=localhost)
included: /Volumes/Source Code/playground/stackoverflow/get_available_node.yml for localhost => (item=example.com)
included: /Volumes/Source Code/playground/stackoverflow/get_available_node.yml for localhost => (item=localhost)
TASK [Try to curl localhost] ******************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "dest": "/dev/null", "elapsed": 0, "gid": 0, "group": "wheel", "mode": "0666", "msg": "Request failed: <urlopen error [Errno 61] Connection refused>", "owner": "root", "size": 0, "state": "file", "uid": 0, "url": "http://localhost"}
...ignoring
TASK [set_fact] *******************************************************************************************************************************************************************
skipping: [localhost]
TASK [Try to curl example.com] ****************************************************************************************************************************************************
ok: [localhost]
TASK [set_fact] *******************************************************************************************************************************************************************
ok: [localhost]
TASK [Try to curl localhost] ******************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "dest": "/dev/null", "elapsed": 0, "gid": 0, "group": "wheel", "mode": "0666", "msg": "Request failed: <urlopen error [Errno 61] Connection refused>", "owner": "root", "size": 0, "state": "file", "uid": 0, "url": "http://localhost"}
...ignoring
TASK [set_fact] *******************************************************************************************************************************************************************
skipping: [localhost]
TASK [debug] **********************************************************************************************************************************************************************
ok: [localhost] => {
"available_domain": "example.com"
}
PLAY RECAP ************************************************************************************************************************************************************************
localhost : ok=9 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=2
At the end, a usable server is in the variable, however, if there are 20 hosts in my original list, it takes a lot of time to loop through them.
Where is my misunderstanding of how the until parameter works? Is there a way to achieve what I'm trying to do?
Using run_once should work, as long as setup is run (ie gather_facts: true), because ansible will remove those hosts which can't be reached for Fact Gathering, from the candidate pool for run_once, and thus only run on the first "up" host. for example:
---
- hosts: all
become: false
run_once: true
gather_facts: true
tasks:
- ping:
$ ansible-playbook -i does,not,exist,localhost, test.yml
will run ping on only one of 4 hosts only: localhost, the only one that's up
PLAY RECAP ********************************************************************
does : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
exist : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
not : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
(you might have to add ansible_connection: local to host_vars/localhost to simulate). If there are multiple hosts up, run_once will only run on the first one from the inventory that's actually up.
Note, if you're doing fact caching, I'm not sure if this will still hold true, because setup might not get run and remove the node from candidate pool. If you need this, an initial ping task through all the servers, followed by the "work" task with run_once, might work (untested), with the default linear strategy.

Register command output as 2 separate variables

I have an Ansible playbook that runs a script over my remote machines.
The script finds log files, determine the application the log file came from (so it would know the destination directory), and uploads the files back to the Ansible server (using scp).
Just because it worth mentioning - there are 2 different playbooks, one for Windows servers, using a PowerShell script, and the other is for Linux servers, using a bash script.
I would like to eliminate the scp part for those scripts, and instead using the fetch module in my playbooks. But I'm facing a problem with that - my scripts generates 2 variables for each application on each server:
the log file, full path.
the destination directory in the Ansible server (determined by the servers name and the application name).
My current playbook looks like that (this is the Windows one):
---
- hosts: <WindowsHosts>
gather_facts: no
tasks:
- name: Find and Copy Windows Applications Logs
script: fetchwinFindLogs.ps1 {{ server_partition }} {{days}} {{ansibleSRV_Port}} {{ansibleSRV_IP}}
register: result
- debug:
var: result
# - fetch: src={{ result }} dest={{ result }}
# with_items: "{{ result.stdout_lines }}"
The output:
PLAY [<WinHost>] *********************************************************************************************************************************************************************************************
TASK [Find and Copy Windows Applications Logs] ***************************************************************************************************************************************************************
changed: [<WinHost>]
TASK [debug] *************************************************************************************************************************************************************************************************
ok: [<WinHost>] => {
"result": {
"changed": true,
"failed": false,
"rc": 0,
"stderr": "",
"stderr_lines": [],
"stdout": "C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18\r\n/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/\r\nC:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18\r\n/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/\r\nC:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18\r\n/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/\r\nC:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18\r\n/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/\r\n",
"stdout_lines": [
"C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18",
"/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/",
"C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18",
"/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/",
"C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18",
"/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/",
"C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18",
"/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
]
}
}
PLAY RECAP ***************************************************************************************************************************************************************************************************
<WinHost> : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
How do I use the 2 separate values gotten from the script, so the fetch module would know to direct each log file from each application to the correct directory in my Ansible server?
This includes, of course, looping over every 2 values, so it would direct the correct log to the correct destination directory (since, again, the first value will always be the full path log, and the second would be the destination directory, for each application separately).
There is possibly plenty of ways to achieve this.
Here are two of them:
Using the extended loop variables and a when condition, you could skip every other item with a when and a modulo % and get the item along with the ansible_loop.nextitem.
Here is an example for that:
- hosts: all
gather_facts: no
tasks:
- debug:
msg:
- "src: {{ item  }}"
- "dest: {{ ansible_loop.nextitem }}"
loop: "{{ result.stdout_lines }}"
when: ansible_loop.index % 2 == 1
loop_control:
extended: yes
vars:
result:
stdout_lines:
- "C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/"
- "C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/"
- "C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/"
- "C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
This yields the recap:
PLAY [all] ********************************************************************************************************
TASK [debug] ******************************************************************************************************
ok: [localhost] => (item=C:\<Maindir>\<App1>\Logs\platform.log.2020-09-18) => {
"msg": [
"src: C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/"
]
}
skipping: [localhost] => (item=/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/)
ok: [localhost] => (item=C:\<Maindir>\<App2>\Logs\platform.log.2020-09-18) => {
"msg": [
"src: C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/"
]
}
skipping: [localhost] => (item=/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/)
ok: [localhost] => (item=C:\<Maindir>\<App3>\Logs\platform.log.2020-09-18) => {
"msg": [
"src: C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/"
]
}
skipping: [localhost] => (item=/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/)
ok: [localhost] => (item=C:\<Maindir>\<App4>\Logs\platform.log.2020-09-18) => {
"msg": [
"src: C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
]
}
skipping: [localhost] => (item=/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/)
PLAY RECAP ********************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Another idea would be to use Python array slicing to separate odd from even elements and Ansible zip filter.
This would be the playbook:
- hosts: all
gather_facts: no
tasks:
- debug:
msg:
- "src: {{ item.0 }}"
- "dest: {{ item.1 }}"
loop: "{{ result.stdout_lines[::2] | zip(result.stdout_lines[1::2]) | list }}"
vars:
result:
stdout_lines:
- "C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/"
- "C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/"
- "C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/"
- "C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18"
- "/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
This yields the recap:
PLAY [all] ********************************************************************************************************
TASK [debug] ******************************************************************************************************
ok: [localhost] => (item=['C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18', '/<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/']) => {
"msg": [
"src: C:\\<Maindir>\\<App1>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App1>/"
]
}
ok: [localhost] => (item=['C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18', '/<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/']) => {
"msg": [
"src: C:\\<Maindir>\\<App2>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App2>/"
]
}
ok: [localhost] => (item=['C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18', '/<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/']) => {
"msg": [
"src: C:\\<Maindir>\\<App3>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App3>/"
]
}
ok: [localhost] => (item=['C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18', '/<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/']) => {
"msg": [
"src: C:\\<Maindir>\\<App4>\\Logs\\platform.log.2020-09-18",
"dest: /<LinuxMainDir>/<logs>/Applications/<serverName>.<App4>/"
]
}
PLAY RECAP ********************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
When I would have a slight preference for the second approach, I could understand it could be less readable for people not used to Python's array slicing.

ansible: failed_when is not working to validate user input

i am trying ansible playbook to prompt for a user input and if condition is not satisfied it should fail & exit.
my playbook is as below.
[ansible#localhost ~]$ cat dummy.yml
---
- name: testing failed_when
hosts: localhost
gather_facts: no
tasks:
- pause:
prompt: "\nPlease ente 1:\n"
register: given
failed_when: given.user_input != 1
- set_fact:
SER: "{{ given.user_input }}"
- fail:
msg: "unacceptable"
when: SER is undefined
and when i execute this, it's getting failed even though i give input as 1..
[ansible#localhost ~]$ ansible-playbook dummy.yml
PLAY [testing failed_when] *********************************************************************************************************************
TASK [pause] ***********************************************************************************************************************************
[pause]
Please ente 1:
:1
fatal: [localhost]: FAILED! => {"changed": false, "delta": 1, "echo": true, "failed_when_result": true, "rc": 0, "start": "2020-05-29 02:52:27.318633", "stderr": "", "stdout": "Paused for 0.02 minutes", "stop": "2020-05-29 02:52:28.556987", "user_input": "1"}
NO MORE HOSTS LEFT *****************************************************************************************************************************
PLAY RECAP *************************************************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[ansible#localhost ~]$
and i have tried using "fail" as shown below, it's not working too.
tasks:
- pause:
prompt: "\nPlease ente 1:\n"
register: given
- set_fact:
SER: "{{ given.user_input }}"
- fail:
msg: "unacceptable"
when: SER != 1
result:
[ansible#localhost ~]$ ansible-playbook dummy.yml
PLAY [testing failed_when] *********************************************************************************************************************
TASK [pause] ***********************************************************************************************************************************
[pause]
Please ente 1:
:1
ok: [localhost]
TASK [set_fact] ********************************************************************************************************************************
ok: [localhost]
TASK [fail] ************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "unacceptable"}
PLAY RECAP *************************************************************************************************************************************
localhost
in both of above cases, i have entered "1" as user input & it's still failing.. Not sure what mistake i did.
please help.
thanks in advance.
The condition when expands by default the variable to string. Either compare SER to string
when: SER != "1"
or convert SER to integer
when: SER|int != 1

How to ignore the connection error in play

I want to continue my playbook to do some other tasks when some hosts are unreachable. However, the ignore_errors seems doesn't work. The debug msg is not printed.
ansible version is 2.5.4. Is there a way to do this in this version?
- name: check accessibility
hosts: myhosts
tasks:
- ping:
ignore_errors: yes
- fail:
msg: "Host {{ansible_hostname}} is not accessible"
when: False
An option would be to ping each 'inventory_hostname' in the block and end the play if the ping fails.
- hosts: myhosts
gather_facts: no
tasks:
- block:
- delegate_to: localhost
command: ping -c1 "{{ inventory_hostname }}"
rescue:
- fail:
msg: "{{ inventory_hostname }} not accessible. End of play."
- debug:
msg: "Host {{ inventory_hostname }} continue play."
- setup:
Notes:
Set 'gather_facts: no', because we are not sure all hosts are available
Use 'inventory_hostname', because of 'gather_facts: no'
use 'setup' module after the 'block' if necessary
Running the playbook with available hosts: test_01, test_02, test_03 and unavailable host test_99 gives (abridged):
TASK [fail]
fatal: [test_99]: FAILED! => {"changed": false, "msg": "test_99 not accessible. End of play."}
TASK [debug]
ok: [test_03] => {
"msg": "Host test_03 continue play."
}
ok: [test_01] => {
"msg": "Host test_01 continue play."
}
ok: [test_02] => {
"msg": "Host test_02 continue play."
}
TASK [setup]
ok: [test_03]
ok: [test_01]
ok: [test_02]
PLAY RECAP
test_01 : ok=3 changed=1 unreachable=0 failed=0
test_02 : ok=3 changed=1 unreachable=0 failed=0
test_03 : ok=3 changed=1 unreachable=0 failed=0
test_99 : ok=0 changed=0 unreachable=0 failed=2

Resources