ansible callback plugins

SCHEDULED: <2020-05-16 Sat>

The latest version of ansible is:


Callback Plugins:

Developing plugins, Developing particular plugin types, Callback plugins:

The CallbackBase class:

What methods are available?

curl | grep def\ v2_


def v2_on_any(self, *args, **kwargs):
def v2_runner_on_failed(self, result, ignore_errors=False):
def v2_runner_on_ok(self, result):
def v2_runner_on_skipped(self, result):
def v2_runner_on_unreachable(self, result):
def v2_runner_on_async_poll(self, result):
def v2_runner_on_async_ok(self, result):
def v2_runner_on_async_failed(self, result):
def v2_playbook_on_start(self, playbook):
def v2_playbook_on_notify(self, handler, host):
def v2_playbook_on_no_hosts_matched(self):
def v2_playbook_on_no_hosts_remaining(self):
def v2_playbook_on_task_start(self, task, is_conditional):
def v2_playbook_on_cleanup_task_start(self, task):
def v2_playbook_on_handler_task_start(self, task):
def v2_playbook_on_vars_prompt(self, varname, private=True, prompt=None, encrypt=None, confirm=False, salt_size=None, salt=None, default=None, unsafe=None):
def v2_playbook_on_import_for_host(self, result, imported_file):
def v2_playbook_on_not_import_for_host(self, result, missing_file):
def v2_playbook_on_play_start(self, play):
def v2_playbook_on_stats(self, stats):
def v2_on_file_diff(self, result):
def v2_playbook_on_include(self, included_file):
def v2_runner_item_on_ok(self, result):
def v2_runner_item_on_failed(self, result):
def v2_runner_item_on_skipped(self, result):
def v2_runner_retry(self, result):
def v2_runner_on_start(self, host, task):

Logitech K780

SCHEDULED: <2020-05-10 Sun>

I’m quite happy with my keyboard, but… the fn keys are swapped by default!

Logitech K780

We can use xev to find out more…


KeyPress event, serial 34, synthetic NO, window 0x200001,
    root 0x203, subw 0x0, time 349417, (155,9), root:(3039,559),
    state 0x0, keycode 180 (keysym 0x1008ff18, XF86HomePage), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False


KeyPress event, serial 34, synthetic NO, window 0x200001,
    root 0x203, subw 0x40000e, time 424031, (376,218), root:(3260,768),
    state 0x0, keycode 70 (keysym 0xffc1, F4), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

Solaar is a Linux manager for Logitech’s devices that connect via a USB Unifying, Lightspeed, or Nano receiver.

I found that I needed version 1.0.2rc2, the version from pypi (1.0.1) and the version from debian buster (0.9.2) were too old.

sudo apt install python3-pyudev
git clone
cd Solaar
sudo bash -c 'umask 022 ; pip3 install .'

I think a reboot was required but I’m not sure…

I’m using the following in my ~/.xsession file:

# turn off fn-swap
sudo solaar config 1 fn-swap off
# keep solaar running so we don't lose our settings when the keyboard sleeps
sudo solaar -w hide &

Notebook tutorial - Part 5: Animations!

SCHEDULED: <2020-05-01 Fri>

Just a bit more reading please:

But also, take a look at the Python tutorial - it’s really nice!

If we bring together everything we have learnt, at a stretch we can start thinking about creating a cool animation.

Here’s one I put together:

Pretty neat huh?

Right, let’s walk through how it was made…


import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML

fig, ax = plt.subplots()

ax.tick_params(axis='x', rotation=90)

data = {}

def animate(i):
    # The animate function is called for each frame of the animation - in this case a frame per day!

    data.setdefault((date1 + datetime.timedelta(days=i)).strftime('%Y-%m-%d'), {})

    # This dataframe is a subset of the results...  e.g. Date of report less than
    # or equal to first date + i days
    df3 = df1[df1["Date of report"] <= date1 + datetime.timedelta(days=i)][["Date of report", "DHB"]].groupby([df1["Date of report"].dt.strftime("%Y-%m-%d"), "DHB"]).size()
    for item in df3.items():
        data.setdefault(item[0][0], {})[item[0][1]] = item[1]

    # print(data)
    # This is what "data" looks like for index 0 (frame 1)
    # e.g. {'2020-02-26': {'Auckland': 1}}

    args = [sorted(data)]
    # We're creating a plot per DHB (?)
    for dhb in dhbs:
        args.append([data[x].get(dhb, 0) for x in data])

    # stackplot expects multiple lists of data, first one being the x axis (dates),
    # then, in our case, a list per dhb (for this time period.)

    ax.legend(dhbs, loc='upper left', fontsize='xx-small')

# Think of an animation as a sequence of graphs (or frames)
ani = animation.FuncAnimation(fig, animate, frames=days)

# Finally, let's create a video!'part-5.mp4', fps=1, dpi=200)

What did we learn?

  • We learnt one way to make an animation and that an animation is simply a sequence of frames (or graphs), can you create your own animation? Have a think about what data you can extract and how it could be presented and send me a copy!

Notebook tutorial - Part 4: Pandas and DataFrames

SCHEDULED: <2020-04-30 Thu>

Time to do some reading, take a look at this page in the Panda’s tutorial:

Do some experimenting:

df1[["Date of report"]].groupby(df1["Date of report"]).count()
df1[["Date of report", "Overseas travel"]].groupby([df1["Date of report"].dt.strftime("%Y-%m-%d"), "Overseas travel"]).size().unstack()
df1[["Date of report", "Last country before return"]].groupby([df1["Date of report"].dt.strftime("%Y-%m-%d"), "Last country before return"]).size().unstack()

What did we learn?

  • We learnt that pandas refers to a table of data as a “DataFrame” and that a subset of a DataFrame can be selected to present different features of the data. Please select some data and share the Python code with me!

Notebook tutorial - Part 3: Markdown, Python 3 and COVID-19

SCHEDULED: <2020-04-29 Wed>

This is Markdown:

# COVID-19

[data source](

This is Python 3:

url = ''

# The first sheet (index 0) is "Confirmed", the header starts at row 4 (index 3).
df1 = pd.read_excel(url, 0, 3)
df1["Date of report"] = pd.to_datetime(df1["Date of report"], format='%d/%m/%Y')

This is your COVID-19 notebook:

If at any time you have issues with newer spreadsheets from you can use the following URL:

What did we learn?

  • We learnt of one way (using the pandas library) to get data into our notebook. Please save your changes and email me a copy of your notebook, we will use this notebook as a basis for part 4. :D

Notebook Tutorial - Part 1: Installing Anaconda

SCHEDULED: <2020-04-27 Mon>

Your data science toolkit

With over 20 million users worldwide, the open-source Individual Edition (Distribution) is the easiest way to perform Python/R data science and machine learning on a single machine. Developed for solo practitioners, it is the toolkit that equips you to work with thousands of open-source packages and libraries.

  1. Download
  2. Windows, MacOS or Linux
  3. Python 3.7
  4. 64-Bit Graphical Installer

Once Anaconda is installed:

jupyter notebook

You should see something like this:


What did we learn?

  • It’s not always easy to install software and the process can be unpredictable, if you manage to get Anaconda installed and running then pat yourself on the back, good job! Please send me a screenshot so that I know that you have completed the first part of this tutorial :)