October 23, 2008

Adding SMF support to your debian package

Services in Nexenta are handled using solaris SMF. This makes it very easy to start and stop services; you dont have to worry about it's dependency on other services, which is taken care of by SMF automatically. This cheetsheet lists how easy it is to use SMF.

dh_installsmf

dh_installsmf is one of Nexenta's addition to Debian's debhelper scripts. This makes it trivial to add SMF support in a debian package that installs a service at /etc/init.d/<service>

We'll take a look at how we can add support to such a package.

XML Manifest file

The SMF framework requires a manifest file, which is an XML file, that provides information regarding the service. This information includes the services that this particular service depends on (or configurations files, etc).

It also lists the commands that need to be run to enable, disable the service, or to set various other parameters. The format of the manifest file is explained here.

The Blastwave package has a good collection of manifest files for various packages. Lets take a look at the manifest for apache2:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">

<service_bundle type="manifest" name="apache2">
<service name="network/apache2" type="service" version="4">
<create_default_instance enabled="false"/>
<single_instance/>

<!-- First of all, if the config file is not present,
then we needn't bother with anything else.  -->
<dependency name="config-file" grouping="require_all" restart_on="none" type="path">
<service_fmri value="file:///etc/apache2/apache2.conf"/>
</dependency>

<!-- If there's no network, then there's no point in running -->
<dependency name="loopback" grouping="require_all" restart_on="error" type="service">
<service_fmri value="svc:/network/loopback:default"/>
</dependency>
<dependency name="physical" grouping="require_all" restart_on="error" type="service">
<service_fmri value="svc:/network/physical:default"/>
</dependency>
<dependency name="fs-local" grouping="require_all" restart_on="none" type="service">
<service_fmri value="svc:/system/filesystem/local"/>
</dependency>
<exec_method type="method" name="start" exec="/lib/svc/method/apache2 start" timeout_seconds="60"/>
<exec_method type="method" name="stop" exec="/lib/svc/method/apache2 stop" timeout_seconds="60"/>
<exec_method type="method" name="refresh" exec="/lib/svc/method/apache2 refresh" timeout_seconds="60"/>
<stability value="Unstable"/>
<template>
<common_name>
<loctext xml:lang="C">Apache2 web server</loctext>
</common_name>
<documentation>
<manpage title="apache2" section="7"/>
<doc_link name="apache.org" uri="http://httpd.apache.org/docs/2.0"/>
</documentation>
</template>
</service>
</service_bundle>

In the above file, we see that apache2 has defined the following dependencies:

  • The file /etc/apache2/apache2.conf
  • The network service (and the physical interface being up)
  • The local filesystem

It also defines three methods start, stop and refresh, which are commands for this particular service (start the webserver, stop the webserver, reload the webserver). They call a script /lib/svc/method/apache2, which brings us to dh_installsmf

debian/rules

The service script /lib/svc/method/&lt;package&gt; is generated by dh-installsmf, so when you create an SMF manifest file for Nexenta, make sure you call that file. dh_installsmf will create a script /lib/svc/method/&lt;package&gt; which is a wrapper over the /etc/init.d/&lt;package&gt; file.

So in our case the debian/rules file in the apache2 package will be modified as

[snip]

rm -f debian/apache2-utils/usr/share/doc/apache2-utils/NEWS.Debian
dh_installinit -a --no-start -r --name=apache2 -- defaults 91 09
dh_installsmf --service apache2 --manifest debian/apache2.xml -papache2.2-common
dh_installcron -a -r --name=apache2
if [ "$(LSB_RELEASE)" = "Ubuntu" ]; then \
dh_strip -a; \
else \
dh_strip -a --dbg-package=apache2-dbg -Napache2-mpm-worker -Napache2-mpm-event -Napache2-mpm-prefork -Napache2-dbg; \
fi
dh_link -a
dh_compress -a
[snip]

The --service argument gives the name of the service, the --manifest points to the manifest file and -p tells it which package the smf changes go into. This is basically the package that provides the /etc/init.d/&lt;package&gt; file.

And that is how we generate SMFed debian packages.