Display Debug output in a clean format Ansible - ansible

I am trying to display the message output of a debug command in a nice format in Ansible. At the moment this is how the output looks:
TASK [stop : Report Status of Jenkins Process] *******************************************************************************************************************************
ok: [localhost] => {
"msg": "Service Jenkins is Running.\nReturn code from `grep`:\n0\n"
}
TASK [stop : debug] **********************************************************************************************************************************************************
ok: [localhost] => {
"msg": {
"changed": false,
"failed": false,
"msg": "Service Jenkins is Running.\nReturn code from `grep`:\n0\n"
}
}
How do I get rid of the '\n' character and replace with a new line?
The code below using the split('\n') does not work.
- name: Checking Jenkins Process
shell: "ps -ef | grep -v grep | grep -v dhclient | grep jenkins"
ignore_errors: yes
register: jenkins_process
- debug:
var: jenkins_process.rc
- name: Report Status of Jenkins Process
fail:
msg: |
Service Jenkins is not found
Return code from `grep`:
{{ jenkins_process.rc }}
when: jenkins_process.rc != 0
register: report
- name: Report Status of Jenkins Process
debug:
msg: |
Service Jenkins is Running.
Return code from `grep`:
{{ jenkins_process.rc }}
when: jenkins_process.rc == 0
register: report
- debug:
msg: "{{ report.split('\n') }}"
- name: Stop Jenkins Service
service:
name: jenkins
state: stopped
Is there a way to display this in a nice way?

You can use the debug callback plugin.
You can specify it on command line:
ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook ...
Or in your default section of your ansible.cfg configuration file:
stdout_callback = debug

Related

How do I add a custom message if a task does not meet the 'when' condition and is skipped?

In this task, I am searching for a file. If there is no file, the task will be skipped.
My question is, how do I write a custom message to output when the task is skipped?
- name: Search for files
win_find:
paths: C:\dataset\
register: data
- debug:
msg: "Data exists"
when: data | json_query('files[*].exists')
- name: set_fact
set_fact:
exists: "{{ data | json_query('files[*].exists') }}"
In a different playbook:
- name: Run if file exists
block:
- name: read content from file
win_shell: C:\day.txt
register: day
when: hostvars['10.11.18.190']['exists']
- name: print message
debug:
msg: "{{ hostvars['10.12.201.20']['day'] }}"
As there is no file, the task is skipped:
TASK [Run if file exists] *********************
skipping: [10.11.18.190] => {
"changed": false,
"skip_reason": "Conditional result was False"
}
TASK [print message] **************************************************************************************
ok: [10.11.18.190] => {
"msg": {
"changed": false,
"skip_reason": "Conditional result was False",
"skipped": true
}
}
As you can see from the output, the variable hostvars['10.12.201.20']['day'] is showing "changed": false, skip_reason, etc. But I do not want this, I want it to output a message like, "File does not exist".
How can I create a custom message for this variable hostvars['10.12.201.20']['day']?
A: Use the 'Do It Yourself' callback plugin community.general.diy. See
shell> ansible-doc -t callback community.general.diy
(or the online documentation)
For example, if the file /tmp/day.txt does not exist the playbook
shell> cat pb.yml
- hosts: localhost
tasks:
- stat:
path: /tmp/day.txt
register: stat_day
- command: cat /tmp/day.txt
register: day
when: stat_day.stat.exists
vars:
ansible_callback_diy_runner_on_skipped_msg: |
skipping: [{{ inventory_hostname }}]
msg: File does not exist.
ansible_callback_diy_runner_on_skipped_msg_color: green
will display the custom message
shell> ANSIBLE_STDOUT_CALLBACK=community.general.diy ansible-playbook pb.yml
PLAY [localhost] *****************************************************************************
TASK [stat] **********************************************************************************
ok: [localhost]
TASK [command] *******************************************************************************
skipping: [localhost]
msg: File does not exist.
PLAY RECAP ***********************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Optionally, you can use the block/rescue construct. See Handling errors with blocks.
For example, in Linux (I don't have access to Windows atm) when you try to access a nonexistent file by the module command on the localhost
- command: cat /tmp/day.txt
register: day
the command will fail
fatal: [localhost]: FAILED! => changed=true
ansible_facts:
discovered_interpreter_python: /usr/bin/python3
cmd:
- cat
- /tmp/day.txt
delta: '0:00:00.010884'
end: '2023-02-14 07:21:50.664051'
msg: non-zero return code
rc: 1
start: '2023-02-14 07:21:50.653167'
stderr: 'cat: /tmp/day.txt: No such file or directory'
stderr_lines: <omitted>
stdout: ''
stdout_lines: <omitted>
Put the command into the block and use the section rescue
- block:
- command: cat /tmp/day.txt
register: day
- debug:
var: day.stdout
rescue:
- debug:
var: ansible_failed_result
Now, if the command fails you'll see
ansible_failed_result:
ansible_facts:
discovered_interpreter_python: /usr/bin/python3
changed: true
cmd:
- cat
- /tmp/day.txt
delta: '0:00:01.007972'
end: '2023-02-14 07:24:43.791343'
failed: true
invocation:
module_args:
_raw_params: cat /tmp/day.txt
_uses_shell: false
argv: null
chdir: null
creates: null
executable: null
removes: null
stdin: null
stdin_add_newline: true
strip_empty_ends: true
msg: non-zero return code
rc: 1
start: '2023-02-14 07:24:42.783371'
stderr: 'cat: /tmp/day.txt: No such file or directory'
stderr_lines:
- 'cat: /tmp/day.txt: No such file or directory'
stdout: ''
stdout_lines: []
You can reduce the output to the standard error
rescue:
- debug:
var: ansible_failed_result.stderr
If the file exists
shell> echo 'This is the content of /tmp/day.txt' > /tmp/day.txt
The next task in the block will display the standard output of the command
day.stdout: This is the content of /tmp/day.txt
Of course, there will be differences in the error messages among the operating systems. Take a look at the data you get and fit the messages to your needs.
I see not direct solution for this problem. But you could do the following:
disable the output of skipped tasks at all, with
[defaults]
display_skipped_hosts = true
In the ansbile.cfg
For details see https://docs.ansible.com/ansible/latest/collections/ansible/builtin/default_callback.html
create a debug task with the message you want to display with an opposite when condition. So it will only run if the other task is skipped.

How to convert to valid JSON when running an Ansible command?

So, I have this list:
ip_range:
- "1.x.x.x/24"
- "2.x.x.x/24"
And I'm trying to pass it on to an AWS cli command as a valid JSON:
- name: list of IPs
set_fact:
allowed_cidrs: "{{ ip_range | ipaddr('network/prefix') }}"
- debug:
msg: "{{ allowed_qualys_cidrs | to_json }}"
- name: send command
command: >
aws wafv2 update-ip-set
--addresses "{{ allowed_cidrs | to_json }}"
That debug prints:
["1.x.x.x/24", "2.x.x.x/24"]
But what the command tries to send is:
"cmd": [
"aws",
"wafv2",
"update-ip-set",
"--addresses",
"[1.x.x.x/24, 2.x.x.x/24]",
]
Which, because the double quotes are gone, is not a valid JSON.
I already tried every possible approach with Ansible and Jinja2, but I can't figure out a way to send that command with a valid JSON.
Use single quotes in your command rather than double quotes:
- name: list of IPs
set_fact:
allowed_cidrs: "{{ ip_range | ipaddr('network/prefix') }}"
vars:
ip_range:
- "1.1.1.1/24"
- "2.2.2.2/24"
- name: send command
command: >-
aws wafv2 update-ip-set
--addresses '{{ allowed_cidrs | to_json }}'
register: _cmd
- debug:
var: _cmd.cmd
Yields:
TASK [list of IPs] **********************************************************
ok: [localhost]
TASK [send command] *********************************************************
changed: [localhost]
TASK [debug] ****************************************************************
ok: [localhost] => {
"_cmd.cmd": [
"aws",
"wafv2",
"update-ip-set",
"--addresses",
"[\"1.1.1.0/24\", \"2.2.2.0/24\"]"
]
}

Loop over list and evaluate element property in Ansible

I have a list with shell lines that I want to execute on inventory hosts so I can determine if the database is working. For the test purposes I have 1 server with PostgreSQL and 1 with MySQL.
This is my playbook so far:
- name: Check db statuses
shell: "{{ item }}"
loop:
- ps -fp $(pgrep -u postgres) | grep /usr/lib/postgresql
- ps -fp $(pgrep -u mysql) | grep mysqld
register: http
ignore_errors: yes
changed_when: item.failed == false
this is failing with:
{
"http": {
"failed": true,
"msg": "The conditional check 'item.failed == false' failed. The error was: error while evaluating conditional (item.failed == false): 'ansible.parsing.yaml.objects.AnsibleUnicode object' has no attribute 'failed'"
}
}
I want to assign only the item.failed==false result in the register variable (http) but ignore the failed ones.
You can't select what will be registered in a loop. Instead, you'll have to evaluate the registered results in the next task(s), e.g.
- hosts: localhost
tasks:
- command: "{{ item }}"
loop:
- /bin/true
- /bin/false
register: http
ignore_errors: true
- debug:
msg: "{{ item.item }} failed: {{ item.failed }}"
loop: "{{ http.results }}"
loop_control:
label: "{{ item.cmd }}"
gives
ok: [localhost] => (item=['/bin/true']) =>
msg: '/bin/true failed: False'
ok: [localhost] => (item=['/bin/false']) =>
msg: '/bin/false failed: True'

How to display values of two different task register variables in ansible

Below is my playbook,
---
- hosts: all
tasks:
- name: asyn task 1 use time command to see diff use when hostname to get faster output
command: sleep 15
async: 2
poll: 0
register: result1
- name: asyn task
command: sleep 2
register: result2
- name: showing result1
debug:
var: result1
var1: result2
- name: debugging output
debug: msg=this is the {‌{ result1 }} and {‌{ result2 }}
# with_items:
# - {‌{ result1 }}
# - {‌{ result2 }}
getting below error,
changed: [vishwa]
TASK [showing result1] **************************************************************************************************
fatal: [rudra]: FAILED! => {"changed": false, "msg": "'var1' is not a valid option in debug"}
fatal: [arya]: FAILED! => {"changed": false, "msg": "'var1' is not a valid option in debug"}
fatal: [vishwa]: FAILED! => {"changed": false, "msg": "'var1' is not a valid option in debug"}
to retry, use: --limit #/home/admin/ansibledemo/asynch.retry
First point, debug module doesn't have an option var1 and so the error from showing result1 task. You probably have figured that out and written debugging output task with msg option.
This brings to the second point, registering status of an asynchronous task. Since you are using poll: 0, the task would be executing in asynchronous mode so the result may not be immediately available to the registered variable. Use async_status to check the result as described here. Also, in your scenario you should use async value more than sleep period.
An example,
- name: Wait for asynchronous job to end
async_status:
jid: '{{ result1.ansible_job_id }}'
register: job_result
until: job_result.finished
retries: 5
Maybe below playbook file could help you to fulfill your requirement. If not then I have some other alternatives too.
---
- hosts: all
gather_facts: false
name: "[ Debug Senario Test ]"
become: true
become_method: sudo
tasks:
- name: "[[ Command Task 1 ]]"
command: "echo Command Task 1"
register: register1
- name: "[[ Command Task 2 ]]"
command: "echo Command Task 2"
register: register2
- name: "[[ Display Registers ]]"
command: "echo {{ item.stdout }}"
with_items:
- "{{ register1 }}"
- "{{register2}}"
register: register3
- debug:
msg: "{{ register3 }}"
debug does not have a parameter var1, or var. You can't just create a parameter for a module. The error message is clear.
If you would like to store the result1 or result2 then use set_fact module.
You are executing a task in async running in the background. Async task follows a fire and forget execution. That task will be triggered and in running state while the other is being triggered. Use 2 https://docs.ansible.com/ansible/latest/modules/async_status_module.html
for fetching the result of the async task.
Ref:https://docs.ansible.com/ansible/2.7/user_guide/playbooks_async.html

Evaluating return code in ansible conditional

I'm working on automating a task which needs to append the latest version of software to a file. I don't want it to do this multiple times for the same version.
It looks at the following example file:
var software releases = new Array(
"4.3.0",
"4.4.0",
"4.5.0",
"4.7.0",
"4.8.0",
"4.11.0",
"4.12.1",
"4.14.0",
"4.15.0",
"4.16.0",
);
the defaults main.yml would pass in something like
VERSION: 4.16.2
code
- name: register version check
shell: cat /root/versions.js | grep -q {{VERSION}}
register: current_version
- debug: msg="The registered variable output is {{ current_version.rc }}"
- name: append to versions.js
lineinfile:
dest: /root/versions.js
regexp: '^\);'
insertbefore: '^#\);'
line: " \"{{VERSION}}\",\n);"
owner: root
state: present
when: current_version.rc == 1
problem: the debug message is evaluating current_version.rc and showing me boolean values based on the grep commands output, but I can't re-use this in the when conditional to determine if the task should be run.
Edit: the output:
PLAY [localhost] **************************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [test | register version check] *****************************************
failed: [localhost] => {"changed": true, "cmd": "cat /root/versions.js | grep -q 3.19.2", "delta": "0:00:00.003570", "end": "2015-12-17 00:24:49.729078", "rc": 1, "start": "2015-12-17 00:24:49.725508", "warnings": []}
FATAL: all hosts have already failed -- aborting
PLAY RECAP ********************************************************************
to retry, use: --limit #/root/site.retry
localhost : ok=1 changed=0 unreachable=0 failed=1
As nikobelia pointed out in the comments, grep returns an exit code of 1 when it doesn't match any lines. Ansible then interprets this (actually any status code other than 0 from a shell/command task) as an error and so promptly fails.
You can tell Ansible to ignore the response code from the shell/command task by using ignore_errors. Although with grep this will ignore actual errors (given by a return code of 2) so instead you might want to use failed_when like this:
- name: register version check
shell: cat /root/versions.js | grep -q {{VERSION}}
register: current_version
failed_when: current_version.rc == 2

Resources