== Some notes on SMF manifests (on OmniOS) and what goes in them
Recently, [[I needed to create a SMF manifest to run a script at boot
https://twitter.com/thatcks/status/694940838472859648]]. In most init
systems, this is simple. SMF is not most init systems.
SMF requires services (including scripts run at boot) to be defined
in XML manifests. Being XML, they are verbose and picky, but
fortunately there are some good general guidelines on what goes in
them; the one I started from is Ben Rockwood's [[An SMF Manifest
Cheatsheet http://www.cuddletech.com/blog/pivot/entry.php?id=182]].
But there are a number of things it didn't say explicitly (or at all)
that I had to find out the hard way, so here's some notes.
First, on OmniOS you'll find most existing SMF manifests under
_/lib/svc/manifest_, especially _/lib/svc/manifest/system_. If you
get confused or puzzled on how to do something, itt's very worth
raiding these files for examples.
What both Ben Rockwood's writeup and the documentation neglects to
mention is that there is a fixed order of elements in the SMF
manifest. The manifest is not just an (XML) bag of properties; the
elements need to come in a relatively specific order. You can get
all sorts of puzzling and annoying errors from '_svccfg validate_'
if you don't know this.
(The error messages probably make total sense to people who
understand XML DTD validation. I am not such a person.)
For just running a script, everyone seems to set things so
there is only a single instance of your SMF service and it's
auto-created:
.pn prewrap on
>
>
(This comes right after the opening __ tag.)
There is probably an art to picking your SMF dependencies. I went
for overkill; in order to get my script run right at the end of
boot, I specified /system/filesystem/local, /milestone/multi-user,
/milestone/network, and for local reasons /network/iscsi/initiator.
'_svcs_' defaults to listing services in start order, so you can
use that to fish around for likely dependencies. Or you can look
at what similar system SMF services use.
(It turns out that you can put multiple FMRIs in a single __
tag, so my SMF manifest is more verbose than it needs to be. They
need to have the same grouping, ((restart_on)), and type, but this
is probably not uncommon.)
Although you might think otherwise, even a single-shot script
needs to have a 'stop' (()) defined, even if it
does nothing. The one that services seem to use is:
> name='stop'
> exec=':true'
> timeout_seconds='3' />
The timeout varies but I suspect it's not important. Omitting this
will cause your SMF manifest to fail validation.
If you just want to run a script from your SMF service, you need what
is called a 'transient' service. How you specify that your service is
a transient one is rather obscure, because it is not something you set
in the overall service description or in the 'start' ((exec_method))
(where you might expect it to live). Instead it's done this way:
>
>
>
This is directions for _svc.startd_, which is responsible for
starting and restarting SMF services. You can thus find some
documentation for it in the ((svc.startd)) manpage, if you already
understand enough about SMF XML manifests to know how to write
properties.
(Since it is an add-on property, not a fundamental SMF XML attribute,
it is not to be found anywhere in the SMF DTD. Isn't it nice that the
SMF documentation points you to the SMF DTD for these things? No, not
particularly.)
Some documentation will suggest giving your SMF service a name in
the _/site/_ overall namespace. I suggest using an organizational
name of some sort instead, because that way you know that a particular
service came from you and was not dropped in from who knows where
(and it's likely to stand out more in eg '_svcs_' output). Other
people creating SMF packages are already doing this; for instance,
[[pkgsrc https://pkgsrc.joyent.com/]] uses _/pkgsrc/_ names.
(This is the kind of entry that I write because I don't want to
have to re-research this. SMF was annoying enough the first time
around.)
=== Sidebar: A quick command cheatsheet
SMF manifests are validated with '_svccfg validate .xml_'.
Expect to use this often.
Once ready to be used, manifests must be imported into SMF, which
is done with '_svccfg import .xml_'. If you specified that
your service should default to disabled when installed (as I did
here), you then need to enable it with the usual '_svcadm enable
/you/whatever_'.
In theory you can re-import manifests to pick up changes. In practice
I have no idea what sort of things are picked up; for example, if
you delete a __ block, does it go away in the imported
version when reimported? I'd have to experiment (or know more about
SMF than I currently do).
Your imported SMF manifest can be completely removed with '_svccfg
delete /you/whatever_'. Normally you'll want to have disabled the
service beforehand. The _svccfg_ manpage makes me slightly nervous
about this in some circumstances that are probably not going to
apply to many people.
(Svccfg has an _export_ operation, but it just dumps out information,
it doesn't remove things.)