In a previous instalment I talked about setting up services on an Onion Omega with the use of a basic init script. While this works fine for many applications, we can instead use procd scripts. Procd init scripts gives us many nice to use features by default such as a restart strategy and the ability to store and read configuration from the UCI system.
As example, lets say we’d want to create a Node.js app as a service and that this service can be configured with a message and a timeout in order for us to be reminded to get up from ur desks once in a while. Our service name will be mynodeservice and it depends on the following script
Place it in
/var/mynodeservice and test it by running on the Omega
$ node /var/mynodeservice.js <your-name>
Creating a basic procd script
Now that we have a working script, we can make a service out of it. Create a file in
/etc/init.d/mynodeservice with the following content
First, it includes the common ‘run commands’ file
/etc/rc.common needed for a service. This file defines several functions that can be used to manage the service lifecycle, it supports old style init scripts as well as procd scripts. In order to tell that we want to use the new style we then set the USE_PROCD flag.
START option basically tell the system when the service should start and stop during startup and shutdown of OpenWRT.
This init script isn’t very useful at the moment but it shows the basic building blocks on which we will develop the script further.
Enabling the service
To tell OpenWRT that we have a new service we would need to run
$ /etc/init.d/mynodeservice enable
This will install a symlink for us in directory
S90mynodeservice which point to our respective service script in
/etc/init.d/. OpenWRT will start the services according the the order of
S* scripts in
/etc/rc.d/. To see the order you could simply run
$ ls -la /etc/rc.d/S*
It is useful to be able to influence the order of startup of services, if our service would be dependent on the network we’d make sure that
the START sequence ‘index’ is at least 1 more than the START sequence of the network service.
The same rules apply for the optional STOP parameters, only this time it defines in which order the services will be shutdown.
To see Which shutdown scripts are activated you can run
$ ls -la /etc/rc.d/K*
You always need to define a START or STOP sequence in your script (you can also define both). If you define a STOP sequence you also want to
define a stop_service() handler in the init script. This handler is usually taking care of cleaning up service resources or persistence of data needed when the service starts again.
Testing the service
Finally, lets just test our service. Open a second shell to the OpenWRT device and run
$ logread -f
This will tail the system logs on the device.
then enable (if you havent done that yet), and start the service.
$ /etc/init.d/mynodeservice enable
After about 5 seconds we should see the message repeat itself in the log, but we didn’t…
We still need to redirect stdout and stderr to logd in order to see the console.log output in the system logs.
Now, when we restart we should see something like
$ logread -f
Setting up a service simple script like above with procd already gives us some advantages
- Common api to manage services
- The service will automatically start at every boot
It’s time to get more personal, and to that we will use OpenWRTs UCI configuration interface. Create a configuration file
/etc/config/mynodeservice with the following content
UCI will immediately pick this up and the config for our service can be inspected like
$ uci show mynodeservice
Also single options can be requested
$ uci get mynodeservice.hello.name
and we can also change specific configuration with UCI
$ uci set mynodeservice.hello.name=Knight
Now, we’ll introduce a couple of changes to the service script in order to read and use the configuration in our script.
Loading service configuration
We can already pass configuration to the node script by passing arguments to it. The only thing we need to do is load the services matching configuration, store the values of the options we need into some variables
and pass them into the command that starts the script.
We can pass new configuration by running
$ uci set mynodeservice.hello.name=Woodrow Wilson Smith
Note that in the service script the arguments are quoted, which allows us to use spaces in the name option.
If we wouldn’t do this, each part of the name would be treated as a separate argument.
Apart from the loading and passing of config to our script we also added
With that line in place we are able to only restart the service whenever our configuration has changed.
$ /etc/init.d/mynodeservice reload
There are a couple of more options that can be configured in a procd scripts ‘instance block’ that might be handy to know about.
I’ll list a few here, but this is by no means covering everything.
respawn your service automatically when it died for some reason.
procd_set_param respawn \
In this example we respawn
if process dies sooner than respawn_threshold, it is considered crashed and after 5 retries the service is stopped
Configure where to store the pid file
procd_set_param pidfile $PIDFILE
Pass environment variables to your process with
procd_set_param env A_VAR=avalue
If you need to set ulimit for your process you can use
procd_set_param limits core="unlimited"
To see the system wide settings for ulimt on an OpenWRT device you can run
$ ulimit -a
To change the user that runs the service you can use
procd_set_param user nobody
A Onion Omega only seems to have a ‘root’ user or ‘nobody’ as the process owner.