The OpenIndiana SMF service management framework is a powerful replacement for the traditional
rc.d scripts (aka "init scripts"). A manifest XML file is created for each service that tells the SMF system enough about the service's details, dependencies, methods and their context to start and stop the service, etc. By default it will auto-restart on crash, manage dependency chains and provide most other features you'd want from a service manager.
To create a new service, the main job is creating a manifest (if one doesn't exist) for your application. Whilst there are many options (TODO provide link to full guide) in most cases, a simple template is enough to get you going.
Quick Example Manifest
As an example lets create a Nginx manifest (Nginx is a fast webserver). I learnt and indeed based this on Joyent's public manifests on their website (TODO provide link), and is what I use myself on a production server.
Each service has a full path-like identifier, for this example this would be a network service and so be path will be
svc://network/nginx, other spaces are for
applications, etc. Each service has an instance that actually runs (usually "
default"), or sometimes several instances. Altogether, each SMF service instance has a unique name – a FMRI (Fault-Management Resource Identifier) like
svc://network/nginx:default. FMRIs can be reduced to unambiguous tokens – for example, our single-instance service with a unique name in the OS can be referred to as just
nginx in various SMF commands.
All manifests live in the
/var/svc/manifest directory tree, from here the service identifier is used like a path.There are lots of existing ones, which can be useful to crib features of similar services to the one you are creating.
For this example we will be creating one in
/var/svc/manifest/network/nginx.xml, so using your favorite editor (I'm using
nano here) create and start editing at that path.
First we have to add the boiler-plate header, informing the XML DTD what the data in this file describes:
Each file can refer to a bundle of services, but for this example we are just adding one with the name path
In most cases we want a default instance to start and that there should only be a single instance at once, so add :
Then add a list of dependecies that are absolutely required for this service to start, the shorter the list, the faster the system will boot. In this case we just need a filesystem and the network stack to be running, so:
Now the actual start and stop commands are required, this is the area that will be most customised per service. For this case all we need is to give it the start up command and kill command for stop. My nginx install is in a directory called
/opt/cp, and I pass it the location of my config file. If its startup hangs for more than 60 seconds (its a daemon) something bad has happened. For stopping it, SMF has a command
:kill that will send a kill message to the instances started with the start method.
Add an API stability tag:
Then to give a bit more human readable text in the service listening and optionally provide man pages etc., add the following and edit to taste:
Finally, close the
service_bundle xml tags:
That's it, save it and the register it with SMF via:
and start the service:
A few twists
Not every service is as simple as this, if the application isn't a daemon (doesn't fork on creation) add this tag:
If you need to set paths, user ID and enviromental variables, you can add a
method_context inside the
exec_method tags (such as
start). For example here is my start method for another service I use:
In this case when I start the service (in the example, a
node.js service), I set the working directory, the creditials and setup a few environment variables without the need for a separate script to setup how this app wants to be.