A pile of endless side projects

A tiny blog on stuff I do

Servicehandler: one library to bring them all...

2020-06-28

I would like to talk about another side project that kept me busy lately (apart from ITAQA, on which I’m still working!): the development of a small Python library to handle and orchestrate services (or daemons) in Linux.

Fantastic bots and where to find them

Lately I developed four Telegram bots using the really nice library python-telegram-bot.
For the ones that don’t know what a Telegram bot is, refer to this page. Briefly, in this context a bot is an application able to interact with users/groups directly on Telegram, answering to messages and accepting commands.

I will probably write about some of these bots in the future, for now I just want to talk about their hosting and management.

Hardware

A bot is a standard application (in this specific case, a Python script). To interact with it at any time, it needs to be constantly running. Two are the possible solutions:

For different reasons1 I choose the second solution: hosting using a Raspberry PI Zero W. With 512MB of RAM and a 1GHz single-core CPU, it’s not exactly a TOP500 PC, but considering the low amount of resources that my bots need, it’s enough. The key points of the Zero are the small size, the built-in WiFi and the possibility to powering it directly through Micro-USB (using a simple phone charger).

Software

Chosen the hardware and installed a Linux distro like Raspberry Pi OS (historically known as Raspbian), the bots need to be configured so they start automatically on system startup.

The easiest way to automatically start applications is to create ad-hoc services. In order to do this systemd, an administrative/configuration suite native in Linux systems, can be used. For every new service a unit file is written and put in /usr/lib/systemd/user/:

[Unit]
Description=My bot

[Service]
ExecStart=/usr/bin/python3 /home/user/bot/main.py
Environment=PATH=/bin:/usr/bin:/usr/local/bin
WorkingDirectory=/home/user/bot/

[Install]
WantedBy=multi-user.target

It’s now sufficient to mark which services need to be started automatically using the command systemctl --user enable MyBot.service.

All done. It suffices to turn the Raspberry on, forget it, to have everything working fine forever.

Great.

There is just a small detail: often2 things don’t go as planned, therefore it would be nice to be able to restart the bots, to check theirs logs, to kill them if needed, and so on. All things easy to do when connected to the same network of the Raspberry, more complex from somewhere else.3

It would be great if these operations were easy to perform from any place, maybe… creating a new bot…

It will be a humble “bot-manager”, with a modest name and a low-key profile picture. I don’t want to create an evil bot overlord.

Mh.

One library to bring them all and in the darkness bind them

A evil bot driven by power bot-manager4 cannot do anything if it’s not able to interact and control systemd services. What it needs is a library to wrap systemctl.

The ones that have already used Python know that there is a library for every need.5 I looked around for something that would suits me. I didn’t find anything useful, I decided to create one.

systemd-servicehandler

The library is called systemd-servicehandler, or just servicehandler.6

(I’m very proud of the banner)

Current state

servicehandler is still in an experimental phase, it’s nothing exceptional but it currently works. There are still some features to implement, together with tests and fixes.

Since there was no such library yet, I also decided to pack and distribute it on PyPI (servicehandler on PyPI), so that it can be used by other developers via pip (pip install servicehandler).

Currently the base functionalities (service abstraction and utilities control methods7) are implemented, making it possible to control a bot (or any service) in the following way:

import servicehandler as sh

# Create a ServiceHandler object that represents the bot service
my_bot = sh.ServiceHandler('Bot','MyBot.service')

# Check bot status
my_bot.state()
<ServiceState.STOPPED: 2>

# Start the bot
my_bot.start()
Bot changed state to ServiceState.STOPPED
<Response.OK: 1>
    
# Stop the bot
my_bot.stop()
Bot changed state to ServiceState.RUNNING
<Response.OK: 1>

Coming soon

Some things to implement:

Like the other projects in this blog, also servicehandler is completely open-source and available on GitHub: servicehandler.

See you soon, thanks for reading!


  1. I know that any virtual machine of the free-tier would be enough. But, I try to maximize the “DIY” approach in my projects. Also, I decided to resurrect the poor RPi Zero that was sleeping in a drawer for years. I assume he is bored 

  2. Always 

  3. It’s of course possible to configure port-forwarding or use VNC, they are both valid solutions 

  4. Who watches the watchers? Of course LordOfTheBots must be controlled manually (through SSH, for example). It must have a robust design, as it should be very stable 

  5. xkcd: Python 

  6. I know I missed my chance to call the library systemd-onering or something similar, but I still have a glimmer of seriousness (laugh track) 

  7. There are methods to start, stop, enable, disable, kill, get stateÂ