Ansible is highly configurable and extendable for users. This post will show us how to use the callback plugins(shipped with ansible) to extend the playbooks. Ansible ships with many great callback plugins, a majority of these plugins are to control the output format of the playbook or to generate some sort of notification. Some examples are printing the output in a more readable format like YAML, producing a JSON output consumed by other tools, directly logging the playbook output to some local file, sending a mail or slack message on playbook completion, etc.
In most cases, these plugins are sufficient to get the desired results; however, if we need further customization, we have to write our callback plugin. I will write another post about writing a custom plugin here.
To see the list of the plugins shipped with the ansible default install, you can run the following command:
ansible-doc -t callback -l
Example:
ansible-doc -t callback -l
amazon.aws.aws_resource_actions summarizes all "resource:actions" completed
ansible.posix.cgroup_perf_recap Profiles system activity of tasks and full execution using cgroups
ansible.posix.debug formatted stdout/stderr display
ansible.posix.json Ansible screen output as JSON
ansible.posix.profile_roles adds timing information to roles
ansible.posix.profile_tasks adds time information to tasks
ansible.posix.skippy Ansible screen output that ignores skipped status
ansible.posix.timer Adds time to play stats
community.general.cgroup_memory_recap Profiles maximum memory usage of tasks and full execution using cgroups
community.general.context_demo demo callback that adds play/task context
community.general.counter_enabled adds counters to the output items (tasks and hosts/task)
community.general.dense minimal stdout output
community.general.diy Customize the output
community.general.elastic Create distributed traces for each Ansible task in Elastic APM
community.general.hipchat post task events to hipchat
community.general.jabber post task events to a jabber server
community.general.log_plays write playbook output to log file
community.general.loganalytics Posts task results to Azure Log Analytics
community.general.logdna Sends playbook logs to LogDNA
community.general.logentries Sends events to Logentries
community.general.logstash Sends events to Logstash
community.general.mail Sends failure events via email
community.general.nrdp Post task results to a Nagios server through nrdp
community.general.null Don't display stuff to screen
community.general.opentelemetry Create distributed traces with OpenTelemetry
community.general.say notify using software speech synthesizer
community.general.selective only print certain tasks
community.general.slack Sends play events to a Slack channel
community.general.splunk Sends task result events to Splunk HTTP Event Collector
community.general.sumologic Sends task result events to Sumologic
community.general.syslog_json sends JSON events to syslog
community.general.unixy condensed Ansible output
community.general.yaml yaml-ized Ansible screen output
community.grafana.grafana_annotations send ansible events as annotations on charts to grafana over http api
default default Ansible screen output
junit write playbook output to a JUnit file
minimal minimal Ansible screen output
oneline oneline Ansible screen output
ovirt.ovirt.stdout Output the log of ansible
theforeman.foreman.foreman Sends events to Foreman
tree Save host events to files
If you want to check the code of these plugins, you can run the following command to get the path of the files containing the code. I consider this helpful while writing your custom plugin or if you are interested in the internals of these plugins.
ansible-doc -t callback -F
Consider I have the following playbook:
---
- hosts: localhost
name: This is play
gather_facts: false
tasks:
- name: "This is task-1"
shell: cat /etc/hosts
register: host
- name: "This is task-2"
debug:
msg: "{{ host.stdout }}"
Now, let’s run the above playbook without any other change in our system. The following output would be printed on the screen. Notice the output of 2nd task in JSON format, while it’s consumable for any tool but not readable easily.
ansible-playbook p1.yml
PLAY [This is play] ****************************************************************************************************************************************************************************************
TASK [This is task-1] **************************************************************************************************************************************************************************************
changed: [localhost]
TASK [This is task-2] **************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "127.0.0.1\tlocalhost\n127.0.1.1\tcontroller\n# The following lines are desirable for IPv6 capable hosts\n::1 ip6-localhost ip6-loopback\nfe00::0 ip6-localnet\nff00::0 ip6-mcastprefix\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters\n192.168.122.211 lb-apiserver.kubernetes.local"
}
PLAY RECAP *************************************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Enabling a callback plugin
To enable any callback plugin shipped by ansible, you will have to tell ansible which plugin to use. This is done via ansible.cfg file. For example, if I want to enable the YAML plugin, I will add the following to my ansible.cfg file.
cat ansible.cfg
[defaults]
stdout_callback = community.general.yaml
If I execute the same playbook again, I will get the following output. That is more readable.
PLAY [This is play] ****************************************************************************************************************************************************************************************
TASK [This is task-1] **************************************************************************************************************************************************************************************
changed: [localhost]
TASK [This is task-2] **************************************************************************************************************************************************************************************
ok: [localhost] =>
msg: |-
127.0.0.1 localhost
127.0.1.1 controller
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
192.168.122.211 lb-apiserver.kubernetes.local
PLAY RECAP *************************************************************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Summary:
- Ansible has great callback plugins shipped out of the box; in this post, I only gave the example of the YAML plugin; please feel free to play around with different plugins to get acquainted and leverage them in your project.
- Also, note that if the plugins in the above list do not solve your requirements, then you can write your callback plugins in python with all the business logic you want.