This post is obsolete

This blog post is quite old, and a lot has changed since then. Meanwhile, I have changed employer, blogging platform, software stack, infrastructure, interests, and more.
You will probably find more recent and relevant information about the topics discussed here elsewhere.
Still, this content is provided here for historical reasons, but please don’t expect it to be current or authoritative at this point.
Thanks for stopping by!


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 (no link, sun.com no longer exists) 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 (no link, sun.com no longer exists) 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):

1
2
3
4
5
<xml>
<dependency grouping="require_all" name="zones" restart_on="none" type="service">
    <service_fmri value="svc:/system/zones"></service_fmri>
</dependency>
</xml>

Brian Leonhard recently blogged about restricting privileges for Solaris services (no link, sun.com no longer exists), 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:

1
2
3
4
5
<xml>
<method_context>
<method_credential privileges="basic,!file_link_any,!proc_info,dtrace_kernel,proc_owner,proc_zone" user="daemon"></method_credential>
</method_context>
</xml>

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

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

(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:

1
2
3
4
5
6
<xml>
<property_group name="script" type="application">
<propval name="directory" type="astring" value="/path/to/media"></propval>
<propval name="command" type="astring" value="/bin/pkill -HUP mt-daapd"></propval>
</property_group>
</xml>

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”:

1
2
3
4
5
6
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 (no link, sun.com no longer exists) 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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 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:

1
2
3
4
5
6
7
# 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 (no link, page no longer exists).

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!


Comments

Commenting is currently not available, because I’d like to avoid cookies on this site. I may or may not endeavor into building my own commenting system at some time, who knows?

Meanwhile, please use the Contact form to send me your comments.

Thank you!


Welcome

This is the blog of Constantin Gonzalez, a Solutions Architect at Amazon Web Services, with more than 25 years of IT experience.

The views expressed in this blog are my own and do not necessarily reflect the views of my current or previous employers.


Copyright © 2022 – Constantin Gonzalez – Some rights reserved.
By using this site you agree to not hold the author responsible for anything related to this site. See Site Info/Imprint for details and our information policy.

This site was built using Pelican, which is written in Python, using a homegrown theme that borrows heavily from Elegant. It is hosted on Amazon S3 and distributed through Amazon CloudFront.