How can I make Ansible show only errors in execution? - ansible

How can I make ansible show only errors inside of some playbook, or even when directly invoked?
I tried suppressing std output but that apparently didn't help, because execution errors seem to be put into standard output instead of error output on Linux.
ansible all -a 'some_command_I_want_to_know_if_it_crashes' 1> /dev/null
I see only errors from Python (exceptions etc.) but not errors from playbook (the red text).

Use the official sample callback plugin called actionable.py.
Put it in the callback_plugins directory and enable stdout-callbacks in ansible.cfg:
[defaults]
stdout_callback = actionable
Just by enabling it you will get much less information in th output, but you can further modify the plugin code to suit your needs.
For example to disable messages on successful tasks completely (regardless if status is ok or changed) change:
def v2_runner_on_ok(self, result):
if result._result.get('changed', False):
self.display_task_banner()
self.super_ref.v2_runner_on_ok(result)
to
def v2_runner_on_ok(self, result):
pass
As Konstantin Suvorov noted, the above ansible.cfg configuration method works for ansible-playbook.
For ansible output you can save the actionable.py as ./callback_plugins/minimal.py to achieve the same results.

You could run the command with actionable callback
ANSIBLE_STDOUT_CALLBACK=actionable ansible all -a 'some_command_I_want_to_know_if_it_crashes'

Related

Is there any way to check a Yml/Yaml file is valid ansible Playbook?

It should check all cases of imports, includes and custom variables. As of now I can see that ansible-playbook playbook.yml --list-tasks fails in few cases when we have custom variables. For example a yml having tasks only should not be a valid play. yml importing those tasks should be treated as valid ansible play.
Because of the way templating etc works, the only way to know for sure beyond basic syntax checking (eg --syntax-check or --list-tasks) is to execute it. --check-mode can tell you some things if your playbook is written correctly to support it, and there are other tools around like ansible-lint that might help, but nothing short of executing the playbook will tell you 100%.

Ansible: TASK - is there an easy way to get Ansible to show the actual path of the source file on failure?

Oftentimes, when I'm running Ansible it will output:
TASK [relative/path/to/directory : name]
fatal: etc...
Now, when I've got a large repo that might be importing in other repos it takes some mental overhead to figure out where this directory is. And when you have to do this many times a day it gets annoying.
Is it possible to get Ansible to simply output the absolute path where the error happens?
Turn on verbose logging:
ansible-playbook <more arguments> -vvvv
This will output a stack trace including the file and line number in case of an error.

How to change ansible verbosity level without changing the command line arguments?

I want to control the verbosity of ansible playbooks using an environment variable or a global configuration item. This is because ansible is called from multiple places in multiple ways and I want to change the logging level for all further executions from the same shell session.
I observed that if I configure ANSIBLE_DEBUG=true ansible will run in debug mode but debug more is extremely verbose and I am only looking for something similar to the -vvv option (DEBUG is more verbose than even -vvvv option)
I tried to look for a variable inside https://github.com/ansible/ansible/blob/devel/lib/ansible/constants.py but I wasn't able to find one this fits the bill.
I see two ways to do this:
alias
alias ansible-playbook="echo 'This is -vv alias'; ansible-playbook -vv"
This way your shell will call ansible-playbook -vv when you type ansible-playbook (and print friendly reminder about alias).
callback plugin
Drop this code as verbosity_env.py file into callback_plugins directory:
from ansible.plugins.callback import CallbackBase
import os
try:
from __main__ import display
except ImportError:
display = None
class CallbackModule(CallbackBase):
def v2_playbook_on_start(self, playbook):
v = os.environ.get('ANSIBLE_VERBOSITY')
if v and display:
display.display('Verbosity is set to {} with environment variable.'.format(v), color='blue')
display.verbosity = int(v)
It is not production quality code, but does the job. This will check ANSIBLE_VERBOSITY environment variable and set display verbosity with its value.
Not sure why I missed to answer this, since a long time ago ansible fully supports ANSIBLE_VERBOSITY=[0|1|2|3|4].
For reference, ansible documentation
You can create/edit ansible.cfg file in the local folder and add in section [defaults]:
[defaults]
verbosity=4
Alternatively you can add the same option in /etc/ansible/ansible.cfg file.
I can't find it documented anywhere other than sorin's answer, but if you set ANSIBLE_VERBOSITY=[0|1|2|3|4] environment variable, ansible-playbook will pick this up and use it, unless you specify the verbosity on the command line.
E.g. in Unix-type shells:
export ANSIBLE_VERBOSITY=2
ansible-playbook my-playbook.yml
I only stumbled upon it because I tried setting ANSIBLE_VERBOSITY='-vv' in a pipeline and Ansible started moaning about it not being an integer!

Specifying a particular callback to be used in playbook

I have created different playbooks for different operations in ansible.
And I have also created different Callback Scripts for different kinds of Playbooks (And packaged them with Ansible and installed).
The playbooks will be called from many different scripts/cron jobs.
Now, is it possible to specify a particular callback script to be called for a particular playbook? (Using a command line argument probably?)
What's happening right now is, all the Callback scripts are called for each playbook.
I cannot put the callback script relative to the location/folder of the playbook because it's already packaged inside the ansible package. Also, all the playbooks are in the same location too.
I am fine with modifying a bit of ansible source code to accommodate it too if needed.
After going through the code of Ansible, I was able to solve it with the below...
In each callback_plugin, you can specify self.disabled = True and the callback wont be called at all...
Also, which calling a playbook, there's an option to parsing extra arguments as key=value pairs. It will be part of the playbook object as extra_vars field.
So I did something like this in my callback_plugin.
def playbook_on_start(self):
callback_plugins = self.playbook.extra_vars.get('callback_plugin', '') // self.playbook is populated in your callback plugin by Ansible.
if callback_plugins not in ['email_reporter', 'all']:
self.disabled = True
And while calling the playbook, I can do something like,
ansible-playbook -e callback_plugin=email_reporter //Note -e is the argument prefix key for extra vars.
If with callback scripts you mean callback plugins, you could decide in those plugins if any playbook should trigger some action.
In the playbook_on_play_start method you have the name of the play, which you could use to decide if further notifications should be processed or not.
playbook_on_stats then is called at the end of the playbook.
SHOULD_TRIGGER = false
class CallbackModule(object):
def playbook_on_play_start(self, name):
if name == "My Cool Play":
SHOULD_TRIGGER = true
def playbook_on_stats(self, stats):
if SHOULD_TRIGGER == true:
do something cool
Please note, playbook_on_play_start is called for every play in your playbook, so it might be called multiple times.
If you are simply running a playbook via script you can do something like this
ANSIBLE_STDOUT_CALLBACK="json" ansible-playbook -i hosts play.yml
You are setting the callback as an environment variable prior to ansible-playbook command running.

Is it possible to execute an ansible playbook from a URL?

I'd love to be able to run ansible-playbook -i <inventory_url> <playbook_url> from my machine, but it doesn't seem to work.
Does anyone know if this is at all possible?
No. You can see the source code here, which shows the playbooks are assumed to be local:
if not os.path.exists(playbook):
raise errors.AnsibleError("the playbook: %s could not be found" % playbook)
if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)):
raise errors.AnsibleError("the playbook: %s does not appear to be a file" % playbook)
Here's the documentation on Python's os.path, showing that is meant for local files.
Ansible itself doesn't let you do this. But Ansible Tower (a commercial product of theirs) does allow you to perform all sorts of Ansible-related tasks, including running playbooks, etc. through a REST interface.

Resources