?

Log in

No account? Create an account

February 11th, 2009

I find SMF (in Solaris and OpenSolaris) to be the best thing to happen to service management since someone decided that runlevels and symlinks were a handy way to control services at startup & shutdown. No more init.d scripts ... win.

An arguable drawback with SMF is that you have to define your service configuration with an XML file, called a service manifest. I think it would be fair to say that most people do what I used to do: copy an existing manifest and change the relevant bits. A simple but practical method, admittedly, but I decided it could be improved upon.

For that reason I recently put together a little tool called Manifold. It is a simple command-line tool, written in Python, that creates the SMF manifest for you after asking you some questions about the service.

The best way to explain what it does is with a demonstration. Here I will use Manifold to create an SMF manifest for memcached, showing how to validate the result and create the service with it.

Using manifold to create an SMF manifest for memcached is easy. Give it an output filename, then it will prompt for all the answers it needs to create the manifest.
$ manifold memcached.xml

The service category (example: 'site' or '/application/database') [site] 

The name of the service, which follows the service category
   (example: 'myapp') [] memcached

The version of the service manifest (example: '1') [1] 

The human readable name of the service
   (example: 'My service.') [] Memcached

Can this service run multiple instances (yes/no) [no] ? yes

Enter value for instance_name (example: default) [default] 

Full path to a config file; leave blank if no config file
  required (example: '/etc/myservice.conf') [] 

The full command to start the service; may contain
  '%{config_file}' to substitute the configuration file
   (example: '/usr/bin/myservice %{config_file}') [] /opt/memcached/bin/memcached -d

The full command to stop the service; may specify ':kill' to let
  SMF kill the service processes automatically
   (example: '/usr/bin/myservice_ctl stop' or ':kill' to let SMF kill
  the service processes automatically) [:kill] 

Choose a process management model:
  'wait'      : long-running process that runs in the foreground (default)
  'contract'  : long-running process that daemonizes or forks itself
                (i.e. start command returns immediately)
  'transient' : short-lived process, performs an action and ends quickly
   [wait] contract

Does this service depend on the network being ready (yes/no) [yes] ? 

Should the service be enabled by default (yes/no) [no] ? 

The user to change to when executing the
  start/stop/refresh methods (example: 'webservd') [] webservd

The group to change to when executing the
  start/stop/refresh methods (example: 'webservd') [] webservd

Manifest written to memcached.xml
You can validate the XML file with "svccfg validate memcached.xml"
And create the SMF service with "svccfg import memcached.xml"


View the resulting manifest:
$ cat memcached.xml 
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<!--
        Created by Manifold
--><service_bundle type="manifest" name="memcached">

    <service name="site/memcached" type="service" version="1">

        
        
        

        <dependency name="network" grouping="require_all" restart_on="error" type="service">
            <service_fmri value="svc:/milestone/network:default"/>
        </dependency>


        <instance name="default" enabled="false">
            

            <method_context>
                <method_credential user="webservd" group="webservd"/>
            </method_context>

            <exec_method type="method" name="start" exec="/opt/memcached/bin/memcached -d" timeout_seconds="60"/>

            <exec_method type="method" name="stop" exec=":kill" timeout_seconds="60"/>

            <property_group name="startd" type="framework">
                
                
                <propval name="duration" type="astring" value="contract"/>
                <propval name="ignore_error" type="astring" value="core,signal"/>
            </property_group>

            <property_group name="application" type="application">
                
            </property_group>

        </instance>
        
        
        
        <stability value="Evolving"/>

        <template>
            <common_name>
                <loctext xml:lang="C">
                    Memcached
                </loctext>
            </common_name>
        </template>

    </service>

</service_bundle>


Now validate the manifest and use it to create the SMF service:
$ svccfg validate memcached.xml
$ sudo svccfg import memcached.xml 
$ svcs memcached
STATE          STIME    FMRI
disabled        9:52:18 svc:/site/memcached:default


The service can be started and controlled using svcadm:
$ sudo svcadm enable memcached
$ svcs memcached
STATE          STIME    FMRI
online          9:52:53 svc:/site/memcached:default
$ ps auxw | grep memcached
webservd 16098  0.0  0.1 2528 1248 ?        S 09:52:53  0:00 /opt/memcached/bin/memcached -d


Find more information at the Manifold project page or download Manifold from pypi.