Working with the Service Management Facility

Working with the Service Management Facility

Introduction

The Service Management Facility is a quite new feature. But sometimes I have the impression that the most used feature is the capability to use old legacy init.d scripts. But once you use SMF with all its capabilities, you see an extremely powerful concept.

init.d

For a long time, the de-facto standard of starting up services was the init.d construct. This concept is based of startup scripts. Depending from their parametrisation they start, stop or restart a service. The definition of runlevels (what has to be started at a certain stage of booting) and the sequencing is done by linking this startup scripts in a certain directory and the naming of link.

This mechanism worked quite good, but has some disadvantages. You can’t define dependencies between the services. You emulate the dependencies by sorting the links, but that’s more of a kludge as a solution. Furthermore the init.d scripts run only once. When the service stops, there are no means to start it again by the system (you have to login to the system and restart it by using the init.d script directly or using other automatic methods)

With init.d a service (like httpd on port 80) is just a consequence of running scripts, not a configurable entity in itself.

Service Management Facility

SMF was invented to solve many of the problems of the old startup mechanism. Most problems from resulting from the init.d framework result from a lack of knowledge of the system about services it’s running. What do I need to run my service? Is this services needed for other services? What is the status of a service? Should I restart another service (e.g. database) to circumvent problems in another service (an old web application for example)? Okay, an expert has the knowledge to do such tasks manually ... but do you want to wake up at night, just to restart this fscking old application?

The concepts of SMF enables the admin to put this knowledge into a machine readable format, thus the machine can act accordingly. This knowledge about services makes the SMF a powerful tool to manage services at your system. SMF enables the system to:

  • starting, restarting and stopping services according to their dependencies

  • resulting from this the system startup is much faster, as services are started in a parallel fashion when possible

  • When a service fails, SMF restarts this service

  • the delegation of tasks like starting, stopping and configuration of services to non-root users

  • and much more

The following tutorial wants to give you some insights to SMF. Have fun!

The foundations of SMF

The additional capabilities of the SMF comes at a price. SMF has to know more about your services. Most of the new components of the SMF has to do with this capabilities. So we have to define some foundations before doing some practical stuff.

Service and Service Instance

At first we start with the service and the service instance. This difference is important. The service is the generic definition how a service is started. The service instance is the exact configuration of a service. A good example is a webserver. The service defines the basic methods how to start or stop an apache daemon, the service instance contains the information, how an specific configuration should work (which port to listen on, the position of the config file). A service can define to allow just one instance, as well you can define, you can have multiple instances of a certain service.

But: A service doesn’t have to be a long running process. Even a script that simply exits after executing (e.g. for some commands to do network tuning) is a special kind of a service in the sense of SMF.

Milestone

A milestone is somehow similar to the old notion of runlevel. With milestones you can group certain services. Thus you don’t have to define each service when configuring the dependencies, you can use a matching milestones containing all the needed services.

Furthermore you can force the system to boot to a certain milestone. For example: Booting a system into the single user mode is implemented by defining a single user milestone. When booting into single user mode, the system just starts the services of this milestone.

The milestone itself is implemented as a special kind of service. It’s an anchor point for dependencies and a simplification for the admin. Furthermore some of the milestones including single-user, multi-user and multi-user-server contain methods to execute the legacy scripts in rc*.d

Fault Manager Resource Identifier

Every service instance and service instance has a unique name in the system do designate it precisely. This name is called Fault Management Resource Identifier. For example the SSH server is called: svc:/network/ssh:default .The FMRI is divided by the : into three parts. The first part designates the resource as an service. The second parts designates the service. The last part designates the service instance. Into natural language: It’s the default configuration of the ssh daemon.

But why is this identifier called Fault Manager Resource Identifier? Fault Management is another important feature in Solaris. The FM has the job to react automatically to failure events. The failure of a service isn’t much different to the failure of a hard disk or a memory chip. You can detect it and you can react to it. So the Fault Management is tightly integrated into the service management.

Service Model

As I mentioned before, not at all services are equal and they have different requirements to starting them. Thus the System Management Facility knows different service models:

Transient service

The simplest service model is transient. You can view it as a script that gets executed while starting the system without leaving a long-lived server process. You use it for scripts to tune or config things on your system. A good example is the script to configure the core dumping via coreadm.

A recommendation at this place: Don’t use the transient model to transform your old startup scripts. Albeit possible, you loose all the advantages of SMF. In this case it would be easier to use the integrated methods to use legacy init.d scripts.

Standalone model

The third service model is the standalone model. The inner workings of this model are really simple. Whenever the forked process exits, SMF will start it again.

Contract service

The standard model for services is contract. This model uses a special facility of the Solaris Operating Environment to monitor the processes

A short digression: Contracts

Did you ever wondered about the /system/contract filesystems. It’s the most obvious sign of the contracts. The contract model is based on a kernel level construct to manage the relationships between a process and other kernel managed resources. Such resources are processor sets, memory, devices and most important for SMF other processes. Process contracts describe the relation between a process and its child process. The contract subsystem generates events available to other processes via listeners. Possible events are:

::: center
::: {#default}
[Event]{.smallcaps} [Description]{.smallcaps}
——————— ——————————————————————–
empty the last process in the contract has exited
process exit a process in the process contract has exited
core a member process dumped core
signal a member process received a fatal signal from outside the
contract a member process received a fatal signal from outside the contract
hwerr a member process has a fatal hardware error

Events of the contract subsystem ::: :::

[]{#default label=”default”}

Your system already use this contracts. Let’s have a look at sendmail.

# ptree -c `pgrep sendmail`
[process contract 1]
  1     /sbin/init
    [process contract 4]
      7     /lib/svc/bin/svc.startd
        [process contract 107]
          792   /usr/lib/sendmail -bd -q15m -C /etc/mail/local.cf
          794   /usr/lib/sendmail -Ac -q15m

With the -c option ptree prints the contract IDs of the processes. In our example, the sendmail processes run under the contract ID 107. With ctstat we can lookup the contents of this contract:

# ctstat -vi 107
CTID    ZONEID  TYPE    STATE   HOLDER  EVENTS  QTIME   NTIME   
107     0       process owned   7       0       -       -       
	cookie:                0x20
	informative event set: none
	critical event set:    hwerr empty
	fatal event set:       none
	parameter set:         inherit regent
	member processes:      792 794
	inherited contracts:   none

Contract 107 runs in the global zone. It’s an process id and it was created by process number 7 (the svc.startd). There wasn’t any events so far. The contract subsystem should only throw critical evens when the processes terminate due hardware errors and when no processes are left. At the moment there are two processes under the control of the contract subsystem (the both processes of the sendmail daemon)

Let’s play around with the contracts:

# ptree -c `pgrep sendmail`
[process contract 1]
  1     /sbin/init
    [process contract 4]
      7     /lib/svc/bin/svc.startd
        [process contract 99]
          705   /usr/lib/sendmail -bd -q15m -C /etc/mail/local.cf
          707   /usr/lib/sendmail -Ac -q15m

You can listen to the events with the ctwatch:

# ctwatch 99
CTID    EVID    CRIT ACK CTTYPE   SUMMARY

Okay, open a second terminal window to your system and kill the both sendmail processes:

# kill 705 707

After we submitted the kill, the contract subsystem reacts and sends an event, that there are no processes left in the contract.

# ctwatch 99 
CTID    EVID    CRIT ACK CTTYPE   SUMMARY
99      25      crit no  process  contract empty

Besides of ctwatch the event there was another listener to the event: SMF. Let’s look for the sendmail processes again.

# ptree -c `pgrep sendmail`
[process contract 1]
  1     /sbin/init
    [process contract 4]
      7     /lib/svc/bin/svc.startd
        [process contract 103]
          776   /usr/lib/sendmail -bd -q15m -C /etc/mail/local.cf
          777   /usr/lib/sendmail -Ac -q15m

Et voila, two new sendmail processes with a different process id and a different process contract ID. SMF has done its job by restarting sendmail.

To summarize things: The SMF uses the contracts to monitor the processes of a service. Based on this events SMF can take action to react on this events. Per default, SMF stops and restart a service, when any member of the contract dumps core, gets a signal or dies due a hardware failure. Additionally the SMF does the same, when there«s no member process left in the contract.

Service State

Fault management brings us to the next important definition. Every service instance has a service state. This state describes a point in the lifecycle of the process:

::: center
::: {#default}
[Service state]{.smallcaps} [Description]{.smallcaps}
—————————– ———————————————————————————————————————————-
degraded The service runs, but somehow the startup didn’t fully succeeded and thus the service has only limited capabilities
disabled >The service was enabled by the admin, and thus SMF doesn’t attempt to start it
online The services is enabled and the bring-up of the service was successful
offline The service is enabled, but the service hasn’t been started so far, as dependencies are not fulfilled.
maintenance The service didn’t started properly and exited with an error code other than 0. For example because of typos in config files
legacy_run This is an special service state. It’s used by the SMF for services under the control of the restarter for legacy init.d scripts

Description of service states ::: :::

[]{#default label=”default”}

Each service under the control of the SMF has an service state throughout it whole lifetime on the system.

Service Configuration Repository

All the configurations about the services in the Service Configuration Repository. It’s the central database regarding the services. This database is backed up and snapshotted in a regular manner. So it’s easy to fall back to a known running state of the repository (after you or a fellow admin FOOBARed the service configuration)

Dependencies

The most important feature of SMF is the knowledge about dependencies. In SMF you can define two kinds of dependency in a services:

  • which services this service depends on

  • the services that depend on this service

This second way to define a dependency has an big advantage. Let’s assume, you have a new service. You want to start it before an other service. But you don’t want to change the object itself (perhaps, you need this service only in one special configuration and the normal installation doesn’t need your new service ... perhaps it’s the authentication daemon for a hyper-special networking connection ;)). By defining, that another service depends on your service, you don’t have to change the other one.

I will show you how to look up the dependencies in the practical part of this tutorial.

Master Restarter Daemon and Delegated Restarter

Okay, now you have all the data. But you need someone to do something: For this task you have the SMF Master Restarter Daemon. This daemon reads the Service Configuration Repository and acts accordingly. It starts a services when all its dependencies are fulfilled. By this simple rule all services will be started in the process of booting until there are no enabled services left in the offline state.

But not all processes are controlled by the Master Restarter. The Master Restarted can delegate this task to other restarters, thus the are called SMF Delegated Restarter Daemons.

Delegated Restarter for inetd services

The most obvious example for such an delegated restarter is inetd, the daemon to start network demons only on demand. One important effect of this is a change in behavior of the inetd. <code>inetd.conf</code> isn’t used to control inetd anymore. The Solaris services which were formerly configured using this file are now configured via SMF. So you don’t edit the inetd.conf to disable or enable an inetd service. You use the same commands like for all other services.

Enough theory

Enough theory, let’s do some practical stuff ...

Working with SMF

After so much theory SMF may look a little bit complex but it isn’t. For the admin it’s really simple. You can control the complete startup of the system with just a few commands.

What’s running on the system

At first let’s have a look on all services running on the system:

# svcs
legacy_run     10:04:44 lrc:/etc/rc3_d/S84appserv
disabled       10:04:22 svc:/system/xvm/domains:default
online         10:03:48 svc:/system/svc/restarter:default
offline        10:03:54 svc:/network/smb/server:default

This is only a short snippet of the configuration. The output of this command is 105 lines long on my system. But you services in several service states in it. For example I hadn’t enabled xvm on my system (makes no sense, as this Solaris is already virtualized, and the smb server is still online.

Let’s look after a certain service

 #  svcs name-service-cache
STATE          STIME    FMRI
online         10:08:01 svc:/system/name-service-cache:default

The output is separated into three columns. The first shows the service state, the second the time of the last start of the service. The last one shows the exact name of the service.

Starting and stopping a service

Okay, but how do I start the service, how do I use all this stuff:let’s assume, you want to disable sendmail. At first we check the current state:

# svcs sendmail
STATE          STIME    FMRI
online         10:23:19 svc:/network/smtp:sendmail

Now we disable the service. It’s really straight forward:

# svcadm disable sendmail

Let’s check the state again.

# svcs sendmail
STATE          STIME    FMRI
disabled       10:23:58 svc:/network/smtp:sendmail

Okay, a few days later we realize that we need the sendmail service on the system. No problem we enable it again:

# svcadm enable  sendmail
# svcs sendmail
STATE          STIME    FMRI
online         10:25:30 svc:/network/smtp:sendmail

The service runs again. Okay, we want to restart the service. This is quite simple, too

# svcadm restart sendmail
# svcs sendmail
STATE          STIME    FMRI
online*        10:25:55 svc:/network/smtp:sendmail
# svcs sendmail
STATE          STIME    FMRI
online         10:26:04 svc:/network/smtp:sendmail

Did you notice the change in the STIME column. The service has restarted. By the way: STIME doesn’t stand for "start time". It’s a short form for "State Time". It shows, when the actual state of the services was entered.

Okay, now let’s do some damage to the system. We move the config file for sendmail, the glorious sendmail.cf. The source of many major depressions under sys admins.

# mv /etc/mail/sendmail.cf /etc/mail/sendmail.cf.old
# svcadm restart sendmail
# svcs sendmail
STATE          STIME    FMRI
offline        10:27:09 svc:/network/smtp:sendmail

Okay, the service went in the offline state. Offline? At first, the maintenance state would look more sensible. But let’s have a look in some diagnostic informations. With svcs -x you can print out fault messages regarding services.

# svcs -x
svc:/network/smtp:sendmail (sendmail SMTP mail transfer agent)
 State: offline since Sun Feb 24 10:27:09 2008
Reason: Dependency file://localhost/etc/mail/sendmail.cf is absent.
   See: http://sun.com/msg/SMF-8000-E2
   See: sendmail(1M)
   See: /var/svc/log/network-smtp:sendmail.log
Impact: This service is not running.

The SMF didn’t even try to start the service. There is an dependency implicit to the service.

 svcprop sendmail
config/value_authorization astring solaris.smf.value.sendmail
config/local_only boolean true
config-file/entities fmri file://localhost/etc/mail/sendmail.cf
config-file/grouping astring require_all
config-file/restart_on astring refresh
config-file/type astring path
[..]

The service configuration for sendmail defines a dependency to the config-file /etc/mail/sendmail.cf. Do you remember the definition of the service states? A service stays in offline mode until all dependencies are fulfilled. We renamed the file, the dependencies isn’t fulfilled. The restart leads correctly to the "offline state"

Okay, we repair the damage:

# mv /etc/mail/sendmail.cf.old /etc/mail/sendmail.cf

And now we restart the service

# svcadm refresh sendmail
# svcs sendmail
STATE          STIME    FMRI
online         10:33:54 svc:/network/smtp:sendmail

All is well, the service in online again

Automatic restarting of a service

Okay, let’s test another capability of the SMF. The kill the sendmail daemon.

# svcs sendmail
STATE          STIME    FMRI
online         10:33:54 svc:/network/smtp:sendmail
# pkill "sendmail"
# svcs sendmail
STATE          STIME    FMRI
online         10:38:24 svc:/network/smtp:sendmail

The SMF restarted the daemon automatically as you can see from the stime-column

Obtaining the configuration of a service

Okay, as I wrote before every service has some configuration in the SMF Service Configuration Repository. You can dump this configuration with the svcprop command. Let’s print out the configuration for the name service cache:

# svcprop svc:/system/name-service-cache:default
general/enabled boolean false
general/action_authorization astring solaris.smf.manage.name-service-cache
[..]
restarter/state astring online
restarter/state_timestamp time 1203844081.231748000
general_ovr/enabled boolean true

Dependencies

But how do I find out the dependencies between services. The svcadm commands comes to help:

The -d switch shows you all services, on which the service depends. In this example we check this for the ssh daemon.

# svcs -d ssh
STATE          STIME    FMRI
disabled        8:58:07 svc:/network/physical:nwam
online          8:58:14 svc:/network/loopback:default
online          8:58:25 svc:/network/physical:default
online          8:59:32 svc:/system/cryptosvc:default
online          8:59:55 svc:/system/filesystem/local:default
online          9:00:12 svc:/system/utmp:default
online          9:00:12 svc:/system/filesystem/autofs:default</code></

To check, what services depend on ssh, you can use the -D switch:

# svcs -D ssh
STATE          STIME    FMRI
online          9:00:22 svc:/milestone/multi-user-server:default

There is no further service depending on ssh. But the milestone <code>multi-user-server</code> depends on ssh. As long the ssh couldn’t started successfully, the multi-user-server milestone can’t be reached.

Developing for SMF

Okay, now you know how to do basic tasks. But how to use SMF for your own applications. I will use OpenVPN as an example.

Prerequisites

A good source for this program is Blastwave[^1]. Please install the package tun and openvpn

I want to show a running example, thus we have to do some work. It will be just a simple static shared key configuration, as this is a SMF tutorial, not one for OpenVPN. We will use theoden and gandalf again. gandalf will be the server. theoden the client.

10.211.55.201 gandalf
10.211.55.200 theoden

Preparing the server

Okay ... this is just a short configuration for an working OpenVPN server.

# mkdir /etc/openvpn
# cd /etc/openvpn
# openvpn --genkey --secret static.key
# openvpn --dev tun --ifconfig 192.16.1.1 172.16.1.2 --secret static.key --daemon
# scp static.key jmoekamp@10.211.55.200:/tmp/static.key

Now just leave this terminal this way.

Preparing the client

Okay, we need some basic configurations to get the client side of OpenVPN working, even when it’s under control of the SMF ;)

# mkdir /etc/openvpn
# mv /tmp/static.key /etc/openvpn
# cd /etc/openvpn/
# ls -l
total 2
-rw-------   1 jmoekamp other        636 Feb 27 16:11 static.key
# chown -R root:root /etc/openvpn
# chmod 600 static.key

Before working with SMF itself

At first I remove this stinking init.d links. We don’t need them anymore:

# rm /etc/rc0.d/K16openvpn
# rm /etc/rc1.d/K16openvpn
# rm /etc/rc2.d/S60openvpn
# rm /etc/rcS.d/K16openvpn

Okay, and now let’s hack the startup script.…? Wrong! SMF can do many task for you, but this needs careful planing. You should answer yourself some questions:

  1. What variables make a generic description of a service to a specific server?

  2. How do I start the process? How do I stop them? How can I force the process to reload its config?

  3. Which services are my dependencies? Which services depend on my new service?

  4. How should the service react in the case of a failed dependency?

  5. What should happen in the case of a failure in the new service.

Okay, let’s answer this questions for our OpenVPN service. The variables for our OpenVPN client are the hostname of the remote hosts and the local and remote IP of the VPN tunnel . Besides of this the filename of the secret key and the tunnel device may differ, thus it would be nice to keep them configurable.

Starting openvpn is easy. We have just to start the openvpn daemon with some command line parameters. We stop the service by killing the process. And a refresh is done via stopping and starting the service.

We clearly need the networking to use a VPN service. But networking isn’t just bringing up the networking cards. You need the name services for example. So make things easier, the service don’t check for every networking service to be up and running. We just define an dependency for the "network" milestone.

As it make no sense to connect to a server without a network it looks like a sensible choice to stop the service in case of a failed networking. Furthermore it seems a good choice to restart the service when the networking configuration has changed. Perhaps we modified the configuration of the name services and the name of the OpenVPN server resolves to a different IP.

What should happen in the case of a exiting OpenVPN daemon? Of course it should started again.

Okay, now we can start with coding the scripts and xml files.

The Manifest

Okay, as I wrote before, the manifest is the source of the configuration of a service. Thus we have to write such a manifest. The manifest is a XML file. Okay, at first we obey the gods of XML and do some definitions:

# cat openvpn.xml
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type='manifest' name='openvpn'>

Okay, at first we have to name the service:

<service 
name='application/network/openvpn' 
type='service' 
version='1'>

In this example, we define some simple dependencies. As I wrote before: Without networking a VPN is quite useless, thus the OpenVPN service depends on the reached network milestone.

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

In this part of the manifest we define the exec method to start the service. We use a script to start the service. The %m is a variable. It will be substituted with the name of the called action. In this example it would be expanded to =verb=/lib/svc/method/openvpn start=.

<exec_method 
type='method' 
name='start' 
exec='/lib/svc/method/openvpn %m' 
timeout_seconds='2' />

Okay, we can stop OpenVPN simply by sending a SIGTERM signal to it. Thus we can use a automagical exec method. In case you use the :kill SMF will kill all processes in the actual contract of the service.

<exec_method
type='method'
name='stop'
exec=':kill'
timeout_seconds='2'>
</exec_method>

Okay, thus far we’ve only define the service. Let’s define a service. We call the instance theoden2gandalf for obvious names. The service should run with root privileges. After this we define the properties of this service instance like the remote host or the file with the secret keys.

<instance name='theoden2gandalf' enabled='false'>
<method_context>
<method_credential user='root' group='root'>
</method_context>
<property_group name='openvpn' type='application'> 
<propval name='remotehost' type='astring' value='gandalf'>
<propval name='secret' type='astring' value='/etc/openvpn/static.key' />
<propval name='tunnel_local_ip' type='astring' value='172.16.1.2'>
<propval name='tunnel_remote_ip' type='astring' value='172.16.1.1' />
<propval name='tunneldevice' type='astring' value='tun'>
</property_group>
</instance>

At the end we add some further metadata to this service:

<stability value='Evolving' />
<template>
<common_name>
<loctext xml:lang='C'>OpenVPN</loctext>
</common_name>
<documentation>
<manpage title='openvpn' section='1'>
<doc_link name='openvpn.org' uri='http://openvpn.org'>
</documentation>
</template>
</service>
</service_bundle>

I saved this xml file to my home directory under /export/home/jmoekamp/openvpn.xml

The exec method«s script - general considerations

Okay, we referenced a script in the exec method. This script is really similar to a normal init.d script. But there are some important differences. As there«s no parallel startup of services in init.d most scripts for this system bring-up method tend to return as quickly as possible. We have to change this behavior.

Scripts for transient or standalone services should only return in the case of the successful execution of the complete script or when we’ve terminated the process. For services under control of the contract mechanism the script should at least wait until the processes of the service generate some meaningful error messages, but they have to exit, as SMF would consider the service startup as failed, when the script doesn’t return after

There are some general tips:

  • When you write your own stop method don’t implement it in a way that simply kills all processes with a certain name (e.g. pkill "openvpn") this was and is really bad style, as there may be several instances of service. Just using the name to stop the processes would cause unneeded collateral damage.

  • It’s a good practice to include the /lib/svc/share/smf_include.sh. It defines some variables for errorcodes to ease the development of the method scripts.

Implementing a exec method script

We store configuration properties in the Service Component repository. It would be nice to use them for configuration. Thus we have to access them.

Here comes the svcprop command to help:

# svcprop -p openvpn/remotehost svc:/application/network/openvpn:theoden2gandalf
gandalf

With a little bit of shell scripting we can use this properties to use them for starting our processes.

#!/bin/sh

. /lib/svc/share/smf_include.sh

getproparg() { 
val=`svcprop -p $1 $SMF_FMRI` 
[ -n "$val" ] && echo $val 
} 

if [ -z "$SMF_FMRI" ]; then 
echo "SMF framework variables are not initialized." 
exit $SMF_EXIT_ERR 
fi

OPENVPNBIN='/opt/csw/sbin/openvpn'
REMOTEHOST=`getproparg openvpn/remotehost`
SECRET=`getproparg openvpn/secret`
TUN_LOCAL=`getproparg openvpn/tunnel_local_ip`
TUN_REMOTE=`getproparg openvpn/tunnel_remote_ip`
DEVICETYPE=`getproparg openvpn/tunneldevice`

if [ -z "$REMOTEHOST" ]; then 
echo "openvpn/remotehost property not set" 
exit $SMF_EXIT_ERR_CONFIG 
fi

if [ -z "$SECRET" ]; then 
echo "openvpn/secret property not set" 
exit $SMF_EXIT_ERR_CONFIG 
fi

if [ -z "$TUN_LOCAL" ]; then 
echo "openvpn/tunnel_local_ip property not set" 
exit $SMF_EXIT_ERR_CONFIG 
fi

if [ -z "$TUN_REMOTE" ]; then 
echo "openvpn/tunnel_remote_ip property not set" 
exit $SMF_EXIT_ERR_CONFIG 
fi

if [ -z "$DEVICETYPE" ]; then 
echo "openvpn/tunneldevice property not set" 
exit $SMF_EXIT_ERR_CONFIG 
fi

case "$1" in 
'start') 
$OPENVPNBIN --daemon --remote $REMOTEHOST --secret $SECRET --ifconfig $TUN_LOCAL $TUN_REMOTE --dev $DEVICETYPE 
;; 

'stop') 
echo "not implemented"
;; 

'refresh') 
echo "not implemented"
;; 

*) 
echo $"Usage: $0 {start|refresh}" 
exit 1 
;; 

esac 
exit $SMF_EXIT_OK

I saved this script to my home directory under /export/home/jmoekamp/openvpn.

Installation of the new service

Okay, copy the script to /lib/svc/method/:

# cp openvpn /lib/svc/method
# chmod +x /lib/svc/method/openvpn

After this step you have to import the manifest into the Service Configuration Repository:

# svccfg validate /export/home/jmoekamp/openvpn.xml
# svccfg import /home/jmoekamp/openvpn.xml

Testing it

Let’s test our brand new service:

# ping 172.16.1.2
^C

The OpenVPN service isn’t enabled. Thus there is no tunnel. The ping doesn’t get through. Now we enable the service and test it again.

# svcadm enable  openvpn:theoden2gandalf
# ping 172.16.1.2
172.16.1.2 is alive

Voila ... SMF has started our brand new service. When we look into the list of services, we will find it:

# svcs openvpn:theoden2gandalf
STATE          STIME    FMRI
online         18:39:15 svc:/application/network/openvpn:theoden2gandalf

When we look into the process table, we will find the according process:

# /usr/ucb/ps -auxwww | grep "openvpn" | grep -v "grep"
root      1588  0.0  0.5 4488 1488 ?        S 18:39:15  0:00 /opt/csw/sbin/openvpn --daemon --remote gandalf --secret /etc/openvpn/static.key --ifconfig 172.16.1.2 172.16.1.1 --dev tun

Okay, we doesn’t need the tunnel any longer after a few day,thus we disable it:

# svcadm disable openvpn:theoden2gandalf
# /usr/ucb/ps -auxwww | grep "openvpn" | grep -v "grep"
# 

No process left.

Conclusion

Okay, I hope I was able to give you some insights into the Service Management Framework. It’s a mighty tool and this article only scratched on the surface of the topic. But there are several excellent resources out there.

Do you want to learn more

Documentation

Solaris 10 System Administrator Collection - Basic Administration - Managing Services

man page - smf(5)

FAQ

opensolaris.org: SMF(5) FAQ

Other resources

Bigadmin - Solaris Service Management Facility - Quickstart Guide

Bigadmin - Solaris Service Management Facility - Service Developer Introduction

SMF shortcuts on wikis.sun.com

cuddletech.com: An SMF Manifest Cheatsheet