An Introduction to Creating SMF Services
I presume I'm unable to mount the windows share at boot via the /etc/vfstab file because the smb client SMF service that is required hasn't started yet. Well then, why not create my own SMF service, that's dependent on the smb client, to handle the mount for me?
Well, the first problem is that I've never written an SMF service. This Service Developer Introduction, although not quite complete, did get me pointed in the right direction. After some trial and error, I now have my own service that mounts my Windows share at boot. Right or wrong, what follows are the steps I took to get there, and should roughly apply for any type of service you may be interested in creating.
Decide on a Name and Location for the Service Manifest
The service manifest is an XML file that describes your service. Before we begin writing it we need to decide where to put it and what to call it (and optionally what to create it with).
Pick a Location
The service manifest file resides somewhere under /var/svc/manifest. The existing smb client service manifest which my service depends on can be found at /var/svc/manifest/network/smb/client.xml, so this seems like a logical location to put my new service manifest.
Pick a Name
I'm going to call my service integrity, named after the Windows machine to which I'm connecting. So my service manifest will be /var/svc/manifest/network/smb/integrity.xml.
Get a Good XML Editor
OK, this is optional, but I hate XML. One thing that makes working with it bearable is a good XML editor that will parse the DTD and provide code completion, syntax checking and validation. I will be using NetBeans. Since we'll be editing a privilged directory, start it from the terminal using "pfexec netbeans".
Write the Service Manifest
The Service Manifest file has several required sections, which I'll introduce piece by piece. As I build up the file from scratch, each new piece that I introduce will be shown in bold type.
Define the DOCTYPE
Add the following two lines to the beginning of the XML file. If you've decided to use an XML editor, it will parse the DTD to provide code completion, etc.
<?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
Define the Service Bundle
The service bundle has two attributes, type and name. Since we're creating a service manifest, our type will be 'manifest'. The name is arbitrary - I'm using 'integrity':
<?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <service_bundle type="manifest" name="integrity"> </service_bundle>
Define the Service
Here we'll simply give our service a name, version and type:
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="network/smb/integrity"
type="service"
version="1" >
</service>
</service_bundle>
Identify if the Service may have Multiple Instances
If I had multiple Windows shares to mount, this may be true. For now, to keep things simple, I'm going with a single instance:
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
</service>
</service_bundle>
Define the Dependencies (if any)
In my case, there's no point in trying to connect to the Windows share if the SMB client isn't running:
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
<!--
Dependencies. The SMB client must be enabled before shares can be
mounted.
-->
<dependency
name="client"
type="service"
grouping="reqiure_all"
restart_on="none">
<service_fmri value="svc:/network/smb/client"/>
</dependency>
</service>
</service_bundle>
Note, I've configured this service to never restart. I could possibly look into making the service more robust in the future, but this will serve my needs for now.
Define the Instance Name
My service has a single default instance. The guidelines recommend that all services be delivered as disabled, unless they are critical to system boot. I'm not really "delivering" this service to anyone but myself, but I've followed that convention:
<?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <service_bundle type="manifest" name="integrity"> <service name="integrity" type="service" version="1" > <single_instance/> <!-- Dependencies. The SMB client must be enabled before shares can be mounted. --> <dependency name="client" type="service" grouping="reqiure_all" restart_on="none"> <service_fmri value="svc:/network/smb/client"/> </dependency> <instance name="default" enabled="false"> </instance> </service> </service_bundle>
Define the Start and Stop Methods
This is the meat of the service, the job we're asking it to do. The service could call a script, but in my case I simply want to run mount and umount commands:
<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
<!--
Dependencies. The SMB client must be enabled before shares can be
mounted.
-->
<dependency
name="client"
type="service"
grouping="reqiure_all"
restart_on="none">
<service_fmri value="svc:/network/smb/client"/>
</dependency>
<instance name="default" enabled="false">
<!-- Start method: mounts the share -->
<exec_method
type="method"
name="start"
exec="mount //integrity.local/MyDocuments"
timeout_seconds="30"/>
<!-- Stop method: umounts the share -->
<exec_method
type="method"
name="stop"
exec="umount //integrity.local/MyDocuments"
timeout_seconds="30" />
</instance>
</service>
</service_bundle
Define the Property Group
Since this is a configuration service (no processes are started), we have to specify its type in the manifest as transient. If we were writing a service for a process, this entry could be left out:
<⁞?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
<!--
Dependencies. The SMB client must be enabled before shares can be
mounted.
-->
<dependency
name="client"
type="service"
grouping="require_all"
restart_on="none">
<service_fmri value="svc:/network/smb/client"/>
</dependency>
<instance name="default" enabled="false">
<!-- Start method: mounts the share -->
<exec_method
type="method"
name="start"
exec="mount //integrity.local/MyDocuments"
timeout_seconds="30"/>
<!-- Stop method: umounts the share -->
<exec_method
type="method"
name="stop"
exec="umount //integrity.local/MyDocuments"
timeout_seconds="30" />
<property_group name="startd" type="framework">
<propval name="duration" type="astring" value="transient"/>
</property_group>
</instance>
</service>
</service_bundle>
Describe the Service
Finally we describe the service. This is the information that will appear when we query the service using the svcs command:
<?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <service_bundle type="manifest" name="integrity"> <service name="integrity" type="service" version="1" > <single_instance/> <!-- Dependencies. The SMB client must be enabled before shares can be mounted. --> <dependency name="client" type="service" grouping="reqiure_all" restart_on="none"> <service_fmri value="svc:/network/smb/client"/> </dependency> <instance name="default" enabled="false"> <!-- Start method: mounts the share --> <exec_method type="method" name="start" exec="mount //integrity.local/MyDocuments" timeout_seconds="30"/> <!-- Stop method: umounts the share --> <exec_method type="method" name="stop" exec="umount //integrity.local/MyDocuments" timeout_seconds="30" /> <property_group name="startd" type="framework"> <propval name="duration" type="astring" value="transient"/> </property_group> </instance> <template> <common_name> <loctext xml:lang="C"> integrity.local smb share configuration </loctext> </common_name> </template> </service> </service_bundle>
Check and Validate Your XML
If you are using an XML editor such as NetBeans, verify your XML parses correctly and validates against the DTD.
Install the Service
Once the service is defined, it needs to be installed. This can be done with the svccfg command as follows:
svccfg import /var/svc/manifest/network/smb/integrity.xml
Manage Your Service
You can then manage your service like any other.
Query
bleonard@opensolaris:~$ svcs integrity STATE STIME FMRI disabled 12:43:40 svc:/integrity:default
Start
svcadm enable integrity
Verbose Query
bleonard@opensolaris:~$ svcs -l integrity fmri svc:/integrity:default name integrity.local smb share configuration enabled true state online next_state none state_time Thu Nov 20 12:43:40 2008 logfile /var/svc/log/integrity:default.log restarter svc:/system/svc/restarter:default dependency require_all/none svc:/network/smb/client (online)
Notice your service even has its own log file...
bleonard@opensolaris:~$ cat /var/svc/log/integrity:default.log [ Nov 20 12:45:57 Enabled. ] [ Nov 20 12:45:57 Executing start method ("mount //integrity.local/MyDocuments"). ] [ Nov 20 12:45:57 Method "start" exited with status 0. ]
And Most Importantly...
It accomplishes it's task, in this case mounting my Windows share at boot:
bleonard@opensolaris:~/IntegrityDocs$ ls Calphalon.odt My Faxes My Videos Our Money.mny Software My Music My eBooks My Pictures
that's cool :) i actually wanted to read and then write something about smf in czech ;)
Posted by goddard on November 21, 2008 at 06:42 AM GMT #
Thanx been looking for a good example of making a SMF service for a while.
Posted by rob on November 21, 2008 at 11:41 AM GMT #
How can we integrate VISUAL PANAL with SMF
Posted by bithin on November 28, 2008 at 05:06 AM GMT #
bithin, can you elaborate on your question? As far as I understand Visual Panels, they only work with SMF services today.
Posted by William Leonard on December 03, 2008 at 09:41 PM GMT #
Beautiful!
You explain so clearly how to create an SMF service, which is something I have wanted to learn how to do for a long time.
Of all the great features Solaris has, SMF is the one that keeps me loyal. I love it!
Posted by Joseph Sniderman on December 25, 2008 at 06:03 PM GMT #
Can I do this in my exec-method "java -jar lightsky.jar"
so it starts the application?, I tried but it didnt work
Posted by Ransford on October 16, 2009 at 12:47 PM GMT #