Working with services

Sometimes it is needed to enable, restart or disable a service across a fleet of devices. This can be handled by distributing a simple script through "Configure -> File distribution" and templating this as follows:

A simple means of enabling/disabling services on group or device level

Sometimes it is important that services can be turned on or off or be restarted for a large group of devices. This can be achieved by running a simple script and templating the respective service name and condition.

The script we use is called service-control.sh and can be seen below. The variable that is exposed here as $STATE could be any of the allowed states such as enable, disable, start, stop or restart. The service name is defined in the $SERVICE variable. In order to be able to work with variables in the script we need to source them into the script with the source command and export from the config file.

This is how the service-control.sh script looks like:

service-control.sh

#!/usr/bin/env bash

source /usr/local/bin/service-control.conf

systemctl {{$STATE}} {{$SERVICE}} 

Next step is to define a template file called service-control.tmpl that delivers the input into the script:

service-control.tmpl

# service template for systemctl services
# run once trigger {{epoch}}

# use start,stop,restart, disable, enable
export STATE="{{service-state}}"

# service name like nodered.service
export SERVICE="{{service-name}}"

If you want to learn more about this templating please see here.

Then the service-control.sh and the service-control.tmpl that is written as service-control.conf need to be in the same file distribution. Activating templating allows the key-value expansion through the qbee UI. We define the desired service state (here we use "restart") and on which service we want to run this (here nodered.service).

Any change will trigger the command to run which is:

bash /usr/local/bin/service-control.sh > /dev/null 2>&1 &

In case you want to restart the same service multiple times nothing would change. That is why we introduced a third key-value pair called "epoch". It is only in the comment, but nevertheless qbee will replace "epoch" with the number you define in the UI (this can also be triggered as an API call). Since this will always be unique and growing it will always force a file change and thus trigger that the script is run.

In the UI this will look as follows:

!qbee-service-monitor

Explaining the "command to run"

The script is defined as a bash script and started by calling bash /usr/local/bin/service-control.sh > /dev/null 2>&1 &. This runs the script in the background and the appendix > /dev/null 2>&1 & pipes bash output to /dev/null. This command will run any time the file is changed or a key-value pair changes. You could also change permissions and run it or even run it as a different user with sudo -u pi ....... Please remember to use chmod 755 /home/pi/myscript.sh before chaining the execution command with &&.

If you frequently control a large number of devices with this we recommend that you use one script per service. Let's assume you want to restart Node-RED on 500 devices some of them might be offline for a week or two. If you commit this action it will happen once the next time a device comes online. So 499 devices might do this more or less immediately while one device that was offline due to some network issue will do this later. But it is guaranteed that as long as this configuration is not changed it will perform a service restart.

For more information please also consult the run-once page.

Why do you use a template file and a script file?

Of course it could be tempting to include the templating directly into the script. However, qbee has problems to change a file execution and run that file in the same command to run. Therefore, you need to source the template variables the way we described above. Doing this in one file might result in an infinite loop of distributing the file.