Home Server Scripting 4: Wrapping DTrace (and other scripts) Into SMF Services

NewMusicSMF.jpg

In the last couple of posts, we used DTrace to notify our media servers and perfected our script a bit.

But the script is still not ready to be used on our home servers yet: It requires manual start and stop, not quite the service oriented automatism we're used to in the Oracle Solaris world.

The next step is to wrap our DTrace script inside a Service Management Facility (SMF) service, then wrap everything into a shell script that will easily install or remove the service whenever we need it.

The Joy of SMF

The Solaris Service Management Facility is one of my favorite features even though it undeservedly doesn't get as much attention as ZFS or Zones. Here's why it's so cool:

  • It lets you list, start, stop and monitor all of your daemons and services with a simple command,
  • It stores all information about your services in a single place, in an open data format,
  • It makes the boot process much more organized, and even parallelizes it for you,
  • And it can do much more for you. Read the SMF(5) man page for more.

In this case, we want to turn last post's DTrace script into an SMF service that can be started, stopped and monitored. Then, we want to wrap everything into a simple shell script that keeps everything together, making it easy to install and de-install.

Let's start by looking at the typical components of an SMF service.

Solaris SMF Service Components

To create an SMF service, we just need three things:

  • An SMF Manifest that describes our service to the system,
  • the actual daemon binary or other script that performs the service (in our case it's a DTrace script),
  • one or more start/stop methods that do the actual work of managing the service. This is what used to be /etc/init.d start/stop scripts in the old days, but you can also tell SMF to just start/kill your process instead.

Wrapping a DTrace Script Into an SMF Service

Sam Falkner blogged about how to wrap a DTrace script inside an SMF service some time ago, including a nice manifest that we can use as a starting point.

Another great help for creating your own SMF manifests is "Manifold": An easy-to-use Python script that asks you some simple questions, then creates the whole manifest for you. Neat!

For our purposes, we should include a dependency on zones (since our media services may should run inside them):

<dependency
  name='zones'
  grouping='require_all'
  restart_on='none'
  type='service'>
  <service_fmri value='svc:/system/zones' />
</dependency>

Brian Leonhard recently blogged about restricting privileges for Solaris services, which contains a lot of knowledge that we can use to restrict our DTrace script to just the set of privileges it needs.

Here's what I came up with after analyzing the privileges that we actually need:

<method_context>
  <method_credential
    user='daemon'
    privileges='basic,!file_link_any,!proc_info,dtrace_kernel,proc_owner,proc_zone' />
</method_context>

We also need to tweak the execution methods to fit our DTrace script's (called dirtrap.d) command line options:

<exec_method
  type='method'
  name='start'
  exec='/lib/svc/method/dirtrap.d %{script/directory} \"%{script/command}\"'
  timeout_seconds='0' />

(We'll discuss filling in the %{script/*} bits later).

And finally, we'll use our own properties for the service, reflecting the path to our media and the command we need to restart our media server daemon with:

<property_group
  name='script'
  type='application'>
 
  <propval
    name='directory'
    type='astring'
    value='/path/to/media' />
  <propval
    name='command'
    type='astring'
    value='/bin/pkill -HUP mt-daapd' />
</property_group>

Wrapping an SMF Service Into a Shell Script Using "Here Documents"

Now that we have wrapped our DTrace script into an SMF service by creating a manifest to go along with it, we're ready to install.

But wait: Like all the other home server management scripts we discussed so far, we'd like to have it all in a single script that includes all the install and de-install work for us, not just the bare components of the service.

Wrapping our DTrace script and the manifest is just a matter of using "Here Documents":

cat > $TMPFILE <<'EOF'
Insert your document here.
Including any $funny $stuff that might be interpreted by the shell.
Which it won't.
At least not until the next line.
EOF

For most shells, there's a useful distinction between putting the end of file marker (which can be any word, we're just using "EOF" as a convention) in quotes and not:

  • Putting the word in quotes will tell the shell to ignore anything inside the Here Document that looks like a shell variable or other substitution. Useful if you want to embed shell scripts inside shell scripts.
  • Leaving out the quotes will enable the shell to substitute any variables and substitutables it encounters inside the Here Document with their values. Useful for last-minute customization of your Here Documents.

Consult the "Here Documents" section of the ksh(1) man page for details.

Customizing SMF Services With Instances and Properties

We may have more than one media server that we want to automatically trigger upon updating their files. This is where SMF service instances come in handy: They allow us to define the service once, then use multiple variations of it, distinguishing them through properties.

In our case, we'll specify two properties per instance:

  • The directory to watch,
  • The name of the process to start.

Here's the piece of code that will create and configure the necessary instances of our service. As an example, we'll use "mediatomb" and "mt-daapd" as our daemons and name the instances after them:

# We want to watch two media directories and restart two associated daemons.
INSTANCES="/export/zones/constant/root/export/home/constant/PowerBookHome/Music/iTunes:mt-daapd /krongi/stuff/media:mediatomb"
 
# Configure and enable all instances of the manifest
for instance in $INSTANCES; do
	directory=$(echo $instance | cut -d: -f1)
	daemon=$(echo $instance | cut -d: -f2)
 
	svccfg -s media-update add $daemon # Add a new service instance
	svccfg -s media-update:$daemon addpg script application # Add a new property group
	svccfg -s media-update:$daemon \
		"setprop script/directory = astring: $directory"
	svccfg -s media-update:$daemon \
		"setprop script/command = astring: \"/bin/pkill -HUP $daemon\""
 
	svcadm enable media-update:$daemon # Enable the new service instance.
done

Notice that the first example instance uses the full path to the loopback mounted media directory inside the zone "constant" (which is: "/export/zones/constant/root/export/home/constant/PowerBookHome/Music/iTunes") because that is the path that dtrace(1M) will see while rsync is updating the media files.

Of course you'll use different paths, just make sure you find the correct and full path to your media directory. It may take some tweaking until you get it right for zones.

One last thing before we finish this article: When de-installing your SMF service in a script, make sure you disable it first in synchronous mode by using the -s switch of svcadm disable. This will let the command wait until the service is really disabled, before proceeding with your script. Otherwise the service may still be (partially) there when you try to delete it, causing unnecessary errors or warnings:

# Disable and delete SMF services
for instance in $INSTANCES; do
	daemon=$(echo $instance | cut -d: -f2)
	svcadm disable -s media-update:$daemon
	svccfg delete media-update:$daemon
done
svccfg delete media-update

Download

The whole script including comments etc. is available as a free, no-cost, complimentary, open-source and eco-responsible download for your hacking pleasure: Download the media_update script.

Conclusion

DTrace scripts can be easily embedded within SMF services. And both the service script and the service manifest can be embedded themselves inside shell scripts for easy, single-script-to-take-care-of administration.

Your Turn

What do you like most about SMF? What are your favorite SMF hacks? What services did you create SMF manifests for? Share your thoughts and experiences in the comments section below!

Stay in Touch!

Did you like this article? Have you found it useful, interesting or entertaining?

Then click here to get free regular updates and help me reach my goal of 1,000 regular blog readers this summer!

Thank you for reading Constant Thinking.