How do I exit Ansible play without error on a condition - ansible

I want to exit without an error (I know about assert and fail modules) when I meet a certain condition. The following code exits but with a failure:
tasks:
- name: Check if there is something to upgrade
shell: if apt-get --dry-run upgrade | grep -q "0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded"; then echo "no"; else echo "yes"; fi
register: upgrading
- name: Exit if nothing to upgrade
fail: msg="Nothing to upgrade"
when: upgrading.stdout == "no"

Since Ansible 2.2, you can use end_play with the meta module:
- meta: end_play
You can also specify when for conditionally ending the play:
- meta: end_play
when: upgrading.stdout == "no"
Note, though, that the task is not listed in the output of ansible-playbook, regardless of whether or not the play actually ends. Also, the task is not counted in the recap. So, you could do something like:
- block:
- name: "end play if nothing to upgrade"
debug:
msg: "nothing to upgrade, ending play"
- meta: end_play
when: upgrading.stdout == "no"
which will announce the end of the play right before ending it, only when the condition is met. If the condition is not met, you'll see the task named end play if nothing to upgrade appropriately skipped, which would provide more info to the user as to why the play is, or is not, ending.
Of course, this will only end the current play and not all remaining plays in the playbook.
UPDATE June 20 2019:
As reto mentions in comments, end_play ends the play for all hosts. In Ansible 2.8, end_host was added to meta:
end_host (added in Ansible 2.8) is a per-host variation of end_play. Causes the play to end for the current host without failing it.
UPDATE Feb 2021: fixed broken link to meta module

Just a little note: meta: end_play ends just the play, not a playbook. So this playbook:
---
- name: 1st play with end play
hosts: localhost
connection: local
gather_facts: no
tasks:
- name: I'll always be printed
debug:
msg: next task terminates first play
- name: Ending the 1st play now
meta: end_play
- name: I want to be printed!
debug:
msg: However I'm unreachable so this message won't appear in the output
- name: 2nd play
hosts: localhost
connection: local
gather_facts: no
tasks:
- name: I will also be printed always
debug:
msg: "meta: end_play ended just the 1st play. This is 2nd one."
will produce this output:
$ ansible-playbook -i localhost, playbooks/end_play.yml
PLAY [1st play with end play] **************************************************
TASK [I'll always be printed] **************************************************
ok: [localhost] => {
"msg": "next task terminates first play"
}
PLAY [2nd play] ****************************************************************
TASK [I will also be printed always] *******************************************
ok: [localhost] => {
"msg": "meta: end_play ended just the 1st play. This is 2nd one."
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

A better and more logical way to solve it may be to do the reverse and rather than fail if there is nothing to upgrade (which is a separate step that does only that) you could append all your upgrading tasks with a conditional depending on the upgrade variable. In essence just add
when: upgrading.changed
to tasks that should be only executed during an upgrade.
It is a bit more work, but it also brings clarity and self contains the logic that affects given task within itself, rather than depending on something way above which may or may not terminate it early.

Lets use what Tymoteusz suggested for roles:
Split your play into two roles where first role will execute the check (and sets some variable holding check's result) and second one will act based on result of the check.
I have created aaa.yaml with this content:
---
- hosts: all
remote_user: root
roles:
- check
- { role: doit, when: "check.stdout == '0'" }
...
then role check in roles/check/tasks/main.yaml:
---
- name: "Check if we should continue"
shell:
echo $(( $RANDOM % 2 ))
register: check
- debug:
var: check.stdout
...
and then role doit in roles/doit/tasks/main.yaml:
---
- name: "Do it only on systems where check returned 0"
command:
date
...
And this was the output:
TASK [check : Check if we should continue] *************************************
Thursday 06 October 2016 21:49:49 +0200 (0:00:09.800) 0:00:09.832 ******
changed: [capsule.example.com]
changed: [monitoring.example.com]
changed: [satellite.example.com]
changed: [docker.example.com]
TASK [check : debug] ***********************************************************
Thursday 06 October 2016 21:49:55 +0200 (0:00:05.171) 0:00:15.004 ******
ok: [monitoring.example.com] => {
"check.stdout": "0"
}
ok: [satellite.example.com] => {
"check.stdout": "1"
}
ok: [capsule.example.com] => {
"check.stdout": "0"
}
ok: [docker.example.com] => {
"check.stdout": "0"
}
TASK [doit : Do it only on systems where check returned 0] *********************
Thursday 06 October 2016 21:49:55 +0200 (0:00:00.072) 0:00:15.076 ******
skipping: [satellite.example.com]
changed: [capsule.example.com]
changed: [docker.example.com]
changed: [monitoring.example.com]
It is not perfect: looks like you will keep seeing skipping status for all tasks for skipped systems, but might do the trick.

The following was helpful in my case, as meta: end_play seems to stop the execution for all hosts, not just the one that matches.
First establish a fact:
- name: Determine current version
become: yes
slurp:
src: /opt/app/CHECKSUM
register: version_check
ignore_errors: yes
- set_fact:
is_update_needed: "{{ ( version_check['checksum'] | b64decode != installer_file.stat.checksum) }}"
Now include that part that should only executed on this condition:
# update-app.yml can be placed in the same role folder
- import_tasks: update-app.yml
when: is_update_needed

You can do this making assert condition false
- name: WE ARE DONE. EXITING
assert:
that:
- "'test' in 'stop'

Running into the same issue, ugly as it might look to you, I decided temporarily to tweak the code to allow for a end_playbook value for the ansible.builtin.meta plugin. So I added below condition to file /path/to/python.../site-packages/ansible/plugins/strategy/__init__.py:
elif meta_action == 'end_playbook':
if _evaluate_conditional(target_host):
for host in self._inventory.get_hosts(iterator._play.hosts):
if host.name not in self._tqm._unreachable_hosts:
iterator.set_run_state_for_host(host.name, IteratingStates.COMPLETE)
sys.exit(0)
msg = "ending playbook"
else:
skipped = True
skip_reason += ', continuing play'
As you can see, pretty simple end effective to stop the entire process using sys.exit(0).
Here's an example playbook to test with:
- name: test
hosts: localhost
connection: local
gather_facts: no
become: no
tasks:
- meta: end_playbook
when: true
- fail:
- name: test2
hosts: localhost
connection: local
gather_facts: no
become: no
tasks:
- debug:
msg: hi
PLAY [test] ****************
TASK [meta] ****************
When I switch to when: false, it skips to next task.
PLAY [test] ********************
TASK [meta] ********************
2023-01-05 15:04:39 (0:00:00.021) 0:00:00.021 ***************************
skipping: [localhost]
TASK [fail] ********************
2023-01-05 15:04:39 (0:00:00.013) 0:00:00.035 ***************************
fatal: [localhost]: FAILED! => changed=false
msg: Failed as requested from task
PLAY RECAP *****************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

Related

How to make Ansible ignore changes in certain lines in file

I have a regular ubuntu VM. My ansible playbook is the following
---
- hosts: linux
tasks:
- name: "Creating a file file.txt"
become: yes
copy: src=./file.txt dest=~/file.txt
notify: restart some_app
handlers:
- name: restart some_app
become: yes
service:
name=some_app
state=restarted
And the contents of my file are
First line
Second line
After creating my VM I apply my ansible playbook. Then I am doing some work on ubuntu VM which could change the contents of file.txt (in Ubuntu VM, not in host). And when my work is done I apply anible playbook again. But I want to restart some_app only when changes are made to the First line in my file and ignore any changes made to the Second line (during some work in ubuntu VM). For example:
If after my work I have (on Ubuntu VM)
First line
Changed Second line
I want ansible to do nothing to this file (I don't want it to be replaced by initial file.txt on my host) and I don't want some_app to be started.
But if I have
Changed First line
Changed Second line
I want ansible to replace only First line and restart some_app, so after applying ansible playbook I would have
First line
Changed Second line
Is it possible to create Second line only once and then make ansible ignore it completly? How can I make this possible using ansible playbook? I can't split my file.txt into two different files or smth like this.
You can create backup and diff the first lines of the files.
For example, if the destination does not exist the module copy reports changed in the registered dictionary. The attribute backup_file is undefined. In this case, changed_when evaluates to True and the handler is notified
- copy:
src: file.txt
dest: ~/file.txt
backup: true
register: copy_result
changed_when:
- copy_result is changed
- copy_result.backup_file is undefined
notify: restart some_app
If the destination exists you want to notify the handler if the first line changes. Create the block below to test the first line. The tasks in the block will be executed only if a backup file is created
- block:
- script:
cmd: '{{ playbook_dir}}/diff_first_line {{ copy_result.backup_file }}'
executable: /bin/bash
register: diff_result
ignore_errors: true
changed_when: diff_result.stdout_lines.0|d('') == '1c1'
notify: restart some_app
- debug:
var: diff_result
when: debug|d(false)|bool
when:
- copy_result.backup_file is defined
Create the script below. The script returns the diff between the first lines of the destination ~/file.txt and the backup file
shell> cat diff_first_line
diff <(head -n 1 ~/file.txt) <(head -n 1 $1)
exit 0
Create the handler for testing
handlers:
- name: restart some_app
debug:
msg: First line of ~/file.txt changed
Example of a complete playbook for testing
shell> cat pb.yml
- hosts: test_24
tasks:
- copy:
src: file.txt
dest: ~/file.txt
backup: true
register: copy_result
changed_when:
- copy_result is changed
- copy_result.backup_file is undefined
notify: restart some_app
- debug:
var: copy_result
when: debug|d(false)|bool
- block:
- script:
cmd: '{{ playbook_dir}}/diff_first_line {{ copy_result.backup_file }}'
executable: /bin/bash
register: diff_result
ignore_errors: true
changed_when: diff_result.stdout_lines.0|d('') == '1c1'
notify: restart some_app
- debug:
var: diff_result
when: debug|d(false)|bool
when:
- copy_result.backup_file is defined
handlers:
- name: restart some_app
debug:
msg: First line of ~/file.txt changed
If the destination does not exist the file will be created and the handler will be notified
shell> ansible-playbook pb.yml
PLAY [test_24] *******************************************************************************
TASK [copy] **********************************************************************************
changed: [test_24]
TASK [debug] *********************************************************************************
skipping: [test_24]
TASK [script] ********************************************************************************
skipping: [test_24]
TASK [debug] *********************************************************************************
skipping: [test_24]
RUNNING HANDLER [restart some_app] ***********************************************************
ok: [test_24] =>
msg: First line of ~/file.txt changed
PLAY RECAP ***********************************************************************************
test_24: ok=2 changed=1 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0
shell> ssh admin#test_24 sudo cat /root/file.txt
First line
Second line
If the destination exists and the first line changed
shell> ssh admin#test_24 sudo cat /root/file.txt
First line changed
Second line
The script in the block will compare the first lines of the files and will notify the handler. Running the playbook with the variable debug=true gives
shell> ansible-playbook pb.yml -e debug=true
PLAY [test_24] *******************************************************************************
TASK [copy] **********************************************************************************
ok: [test_24]
TASK [debug] *********************************************************************************
ok: [test_24] =>
copy_result:
backup_file: /root/file.txt.1520674.2023-01-05#11:00:41~
changed: false
checksum: e23b0534d0708167023aba6f65ef83afe38d52df
dest: /root/file.txt
diff: []
failed: false
gid: 0
group: root
md5sum: cbfa34ef619be185bfbe2b8c8f104d97
mode: '0644'
owner: root
secontext: system_u:object_r:admin_home_t:s0
size: 23
src: /home/admin/.ansible/tmp/ansible-tmp-1672934439.424632-1552928-229786621684419/source
state: file
uid: 0
TASK [script] ********************************************************************************
changed: [test_24]
TASK [debug] *********************************************************************************
ok: [test_24] =>
diff_result:
changed: true
failed: false
rc: 0
stderr: |-
Shared connection to test_24 closed.
stderr_lines:
- Shared connection to test_24 closed.
stdout: |-
1c1
< First line
---
> First line changed
stdout_lines:
- 1c1
- < First line
- '---'
- '> First line changed'
RUNNING HANDLER [restart some_app] ***********************************************************
ok: [test_24] =>
msg: First line of ~/file.txt changed
PLAY RECAP ***********************************************************************************
test_24: ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The handler won't be notified if the first line doesn't change
shell> ssh admin#test_24 sudo cat /root/file.txt
First line
Second line changed
shell> ansible-playbook pb.yml -e debug=true
PLAY [test_24] *******************************************************************************
TASK [copy] **********************************************************************************
ok: [test_24]
TASK [debug] *********************************************************************************
ok: [test_24] =>
copy_result:
backup_file: /root/file.txt.1522339.2023-01-05#11:02:50~
changed: false
checksum: e23b0534d0708167023aba6f65ef83afe38d52df
dest: /root/file.txt
diff: []
failed: false
gid: 0
group: root
md5sum: cbfa34ef619be185bfbe2b8c8f104d97
mode: '0644'
owner: root
secontext: system_u:object_r:admin_home_t:s0
size: 23
src: /home/admin/.ansible/tmp/ansible-tmp-1672934567.8696983-1553096-127236704493791/source
state: file
uid: 0
TASK [script] ********************************************************************************
ok: [test_24]
TASK [debug] *********************************************************************************
ok: [test_24] =>
diff_result:
changed: false
failed: false
rc: 0
stderr: |-
Shared connection to test_24 closed.
stderr_lines:
- Shared connection to test_24 closed.
stdout: ''
stdout_lines: []
PLAY RECAP ***********************************************************************************
test_24: ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Run a handler play and exit play if rc == 0 in ansible

Hi is there a way I can run a handler play then exit the play if rc == 0. It can only do is exit the play using failed_when and proceed if rc != 0. I can't make notify: Service Guard execute. Been play with other approach like creating 2 play notify and exit no luck.
- name: Exit SG server from play
command: /usr/local/cmcluster/bin/cmversion
register: sg_check
notify: Service Guard
failed_when: sg_check.rc == 0
Here is new code I tried
- name: Check if Service Gurad then exit
command: /usr/local/cmcluster/bin/cmversion
register: sg_check
notify: Service Guard
changed_when: sg_check.rc == 0
ignore_errors: true
- meta: end_play
when: sg_check.rc == 0
but I get this:
ERROR! The conditional check 'sg_check.rc == 0' failed. The error was: error while evaluating conditional (sg_check.rc == 0): 'sg_check' is undefined
The error appears to have been in '/home/ansible/linuxpatchingv2/roles/applyPatch/tasks/main.yml': line 9, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
ignore_errors: true
meta: end_play
^ here
Q: "Run a handler play then exit the play if rc == 0"
A: This is not possible to accomplish in one task because a task can't be both changed and failed at the same time. These two actions must be split. For example, in the playbook below the command will succeed, notify the handler, and end the play
shell> cat pb.yml
- hosts: localhost
gather_facts: false
tasks:
- command: "{{ cmd|default('/bin/true') }}"
register: sg_check
notify: Service Guard
changed_when: sg_check.rc == 0
ignore_errors: true
- meta: end_play
when: sg_check.rc == 0
- debug:
msg: Continue
handlers:
- name: Service Guard
debug:
msg: Service Guard notified
gives (abridged)
shell> ansible-playbook pb.yml
...
RUNNING HANDLER [Service Guard] ****
ok: [localhost] =>
msg: Service Guard notified
PLAY RECAP ****
localhost: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The same playbook will continue if the command fails. For example
shell> ansible-playbook pb.yml -e "cmd=/bin/false"
PLAY [localhost] ****
TASK [command] ****
fatal: [localhost]: FAILED! => changed=false
cmd:
- /bin/false
delta: '0:00:00.003035'
end: '2020-08-24 09:33:22.039762'
msg: non-zero return code
rc: 1
start: '2020-08-24 09:33:22.036727'
stderr: ''
stderr_lines: <omitted>
stdout: ''
stdout_lines: <omitted>
...ignoring
TASK [debug] ****
ok: [localhost] =>
msg: Continue
PLAY RECAP ****
localhost: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1

Ansible import_playbook fails with variable undefined error

I am trying to conditionally import a playbook by dynamically generating the name of the playbook to import.
I have the following 2 files:
root#ubuntu:~/test# ls -ltr
total 8
-rw-r--r-- 1 root root 117 sij 2 12:07 child_playbook_1.yaml
-rw-r--r-- 1 root root 210 sij 2 12:11 start.yaml
root#ubuntu:~/test#
start.yaml:
---
- name: main playbook
hosts: localhost
tasks:
- set_fact:
var: "child_playbook"
- debug:
msg: "{{ var }}"
- import_playbook: "{{ var + '_1.yaml' }}"
when: var is defined
child_playbook_1.yaml:
---
- name: child_playbook
hosts: localhost
tasks:
- debug:
msg: "Message from the child playbook"
When I execute start.yaml, I get this as output:
root#ubuntu:~/test# ansible-playbook start.yaml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
ERROR! 'var' is undefined
root#ubuntu:~/test#
Why is var not seen and why do I get this message?
How to overcome this?
To put things into a bit more perspective, the 'var' variable in start.yaml is being dynamically read which means that the name of the playbook to be imported will also be dynamic.
var is a fact defined for localhost (i.e. the only host in the play) in the first play. So it does not exist "globally", only for the given host.
Moreover, imports are made statically at time of playbook parsing (by opposition to includes which are dynamic but to not exist for playbooks).
One could then try to use the var defined for localhost by referencing hostvars['localhost'].var but:
set_fact has not yet run since it is an import.
Moreover hostvars is not yet defined at time of import.
Lastly, you are miss-interpreting how a when clause is actually working. Basically, the condition is passed to all the tasks contained in your included/imported object. So the imported object must exist. If you use an undefined var to get its name, it will always fire an error.
The only solution I currently see to pass a variable playbook name is to use an extra var on the command line. If you want to be able to 'skip' the import when no variable is defined, you could default to an empty playbook.
Here is a dummy empty.yml playbook
---
- name: Dummy empty playbook
hosts: localhost
gather_facts: false
For my tests, I used the same child playbook as in your question except I disabled facts gathering not needed here:
---
- name: child_playbook
hosts: localhost
gather_facts: false
tasks:
- debug: msg="Message from the child playbook"
The new main playbook start.yml looks like this:
---
- name: Play written in start.yml directly
hosts: localhost
gather_facts: false
tasks:
- debug:
msg: "Message from start playbook"
- import_playbook: "{{ var is defined | ternary( var | default('') + '_1.yml', 'empty.yml') }}"
Note than even though we use var is defined as a condition, var will still be interpreted in the ternary filter in all cases (defined or not). So we have to use a default value to make sure we don't have an error when we don't pass a value.
We can now call the playbook with or without an extra var. Here is the result:
$ ansible-playbook start.yml
PLAY [Play written in start.yml directly] *************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Message from main playbook"
}
PLAY [Dummy empty playbook] ***************************************************************************************************************************************************************************************
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ ansible-playbook start.yml -e var=child_playbook
PLAY [Play written in start.yml directly] *************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Message from main playbook"
}
PLAY [child_playbook] *********************************************************************************************************************************************************************************************
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Message from the child playbook"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

How do I handle rollback in case of failure using handlers in Ansible?

I wrote below yml file which will install the SSM and cloudwatch agent but I want to rollback the installation in case of any failures during the installation. I tried use FAIL but not working..Please advise..
---
# tasks file for SSMAgnetInstall
- name: status check
command: systemctl status amazon-ssm-agent
register: s_status
- debug:
msg: "{{ s_status }}"
- name: Get CPU architecture
command: getconf LONG_BIT
register: cpu_arch
changed_when: False
check_mode: no
when: s_status.stdout == ""
ignore_errors: true
- name: Install rpm file for Redhat Family (Amazon Linux, RHEL, and CentOS) 32/64-bit
yum:
name: "https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_386/amazon-ssm-agent.rpm"
state: present
when: s_status.stdout == ""
become: yes
ignore_errors: true
- name: cloud status check
command: systemctl status amazon-cloudwatch-agent
register: cld_status
become: yes
- debug:
msg: "{{ cld_status }}"
- name: Register to cloud watch service
become: yes
become_user: root
service:
name: amazon-ssm-agent
enabled: yes
state: started
- name: copy the output to a local file
copy:
content: "{{ myshell_output.stdout }}"
dest: "/home/ansible/rama/output.txt"
delegate_to: localhost
You should have a look at the the documentation on blocks, more specifically the error handling part. This is the general idea with an oversimplified example, you will have to adapt to your specific case.
The test.yml playbook
---
- hosts: localhost
gather_facts: false
tasks:
- block:
- name: I am a task that can fail
debug:
msg: "I {{ gen_fail | default(false) | bool | ternary('failed', 'succeeded') }}"
failed_when: gen_fail | default(false) | bool
- name: I am a task that will never fail
debug:
msg: I succeeded
rescue:
- name: I am a task in a block played when a failure happens
debug:
msg: rescue task
always:
- name: I am a task always played whatever happens
debug:
msg: always task
Played normally (no fail)
$ ansible-playbook test.yml
PLAY [localhost] ************************************************************************
TASK [I am a task that can fail] ********************************************************
ok: [localhost] => {
"msg": "I succeeded"
}
TASK [I am a task that will never fail] *************************************************
ok: [localhost] => {
"msg": "I succeeded"
}
TASK [I am a task always played whatever happens] ***************************************
ok: [localhost] => {
"msg": "always task"
}
PLAY RECAP ******************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Played forcing a fail
$ ansible-playbook test.yml -e gen_fail=true
PLAY [localhost] ************************************************************************
TASK [I am a task that can fail] ********************************************************
fatal: [localhost]: FAILED! => {
"msg": "I failed"
}
TASK [I am a task in a block played when a failure happens] *****************************
ok: [localhost] => {
"msg": "rescue task"
}
TASK [I am a task always played whatever happens] ***************************************
ok: [localhost] => {
"msg": "always task"
}
PLAY RECAP ******************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0

Condition based execution in ansible

I have a scenario if first condition is successful then execute condition two and if condition two is successful then execute condition three.
Below is what i tried.
vi testme.yml
---
- hosts: all
tasks:
- name: run this command and ignore the result
shell: "grep -ci Hello /tmp/data.out"
register: pingout
ignore_errors: yes
- debug: msg="{{ pingout.rc }}"
- name: run the server if Hello is found in the above task
command: echo "The server is UP since `uptime`"
register: output1
when: pingout.rc == 0
- debug: "{{ output1.stdout }}"
When the string is found I was expecting to see this executed and shown in the output: The server is UP since uptime
However, I do not see this printed in the output.
ansible-playbook -i /tmp/myhost /root/testme.yml
Output:
PLAY [all] ******************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************
ok: [95.76.121.113]
TASK [run this command and ignore the result] *******************************************************************************************************************************
changed: [95.76.121.113]
TASK [debug] ****************************************************************************************************************************************************************
ok: [95.76.121.113] => {
"msg": "0"
}
TASK [run the server if Hello is found in the above task] *******************************************************************************************************************
changed: [95.76.121.113]
TASK [debug] ****************************************************************************************************************************************************************
ok: [95.76.121.113] => {
"msg": "Hello world!"
}
PLAY RECAP ******************************************************************************************************************************************************************
95.76.121.113 : ok=5 changed=2 unreachable=0 failed=0
You do not need to check rc. Ansible knows, when a command failed.
---
- hosts: localhost
connection: local
tasks:
- name: First
shell: "true"
register: first
ignore_errors: yes
- name: Second
shell: "true"
register: second
ignore_errors: yes
when: first is not failed
- name: Third
shell: "true"
register: third
ignore_errors: yes
when: second is not failed
Correct syntax is
- debug: msg="{{ output1.stdout }}"
, or
- debug: var=output1.stdout

Resources