File Coverage

blib/lib/Solaris/SMF/Service.pm
Criterion Covered Total %
statement 14 104 13.4
branch 0 54 0.0
condition n/a
subroutine 5 21 23.8
pod 13 13 100.0
total 32 192 16.6


line stmt bran cond sub pod time code
1             package Solaris::SMF::Service;
2             BEGIN {
3 3     3   11 eval {
4 3         79 require Data::Dumper;
5             }
6             };
7              
8 3     3   15 use warnings;
  3         6  
  3         75  
9 3     3   16 use strict;
  3         4  
  3         97  
10 3     3   16 use Params::Validate qw( validate validate_pos :types );
  3         5  
  3         572  
11 3     3   17 use Carp;
  3         6  
  3         4761  
12              
13             my $debug = $ENV{RELEASE_TESTING} ? $ENV{RELEASE_TESTING} : 0;
14              
15             =head1 NAME
16              
17             Solaris::SMF::Service - Encapsulate Solaris 10 services in Perl
18              
19             =head1 VERSION
20              
21             Version 0.02
22              
23             =cut
24              
25             our $VERSION = '0.02';
26              
27             =head1 SYNOPSIS
28              
29             Interface to Sun's Service Management Facility in Solaris 10. This module provides
30             a wrapper around 'svcs', 'svcadm' and 'svccfg'.
31              
32             The SMF in Solaris is a replacement for inetd as well as the runlevel-based stopping
33             and starting of daemons. Service definitions are stored in an XML database.
34              
35             The biggest advantages in using SMF are the resiliency support, consistent interface and
36             inter-service dependencies it offers. Services that die for any reason can be automatically
37             restarted by the operating system; all services can be enabled or disabled using the same
38             commands; and services can be started as soon as all the services they depend upon have
39             been started, rather than at a fixed point in the boot process.
40              
41             =head1 METHODS
42              
43             =cut
44              
45             sub _svcs {
46 0     0     my $self = shift;
47 0           local $ENV{PATH} = '/bin:/usr/bin:/sbin:/usr/sbin';
48 0 0         open my $svc_list, '-|', " svcs -aH '$self->{FMRI}' 2>/dev/null"
49             or croak 'Unable to query SMF services';
50 0           while ( my $svc_line = <$svc_list> ) {
51 0           my ( $state, $date, $FMRI ) = (
52             $svc_line =~ m/
53             ^
54             ([^\s]+) # Current state
55             [\s]+
56             ([^\s]+) # Date this state was set
57             [\s]+
58             ( (?: svc: | lrc: ) [^\s]+ ) # FMRI
59             \n?
60             $
61             /xms
62             );
63 0 0         if ($FMRI) {
64 0           close $svc_list;
65 0           return ( $state, $date );
66             }
67             }
68 0           croak "Unable to determine status of $self->{FMRI}";
69             }
70              
71             sub _svcprop {
72 0 0   0     $debug && warn( '_svcprop ' . join( ',', @_ ) );
73 0           my $self = shift;
74 0           local $ENV{PATH} = '/bin:/usr/bin:/sbin:/usr/sbin';
75 0 0         open my $svcprop_list, '-|', " svcprop '$self->{FMRI}' 2>/dev/null"
76             or croak 'Unable to query SMF service properties';
77 0           my %properties;
78 0           while ( my $svcprop_line = <$svcprop_list> ) {
79 0           my ( $name, $type, $value ) = (
80             $svcprop_line =~ m/
81             ^
82             ([^\s]+) # Property name
83             [\s]+
84             ([^\s]+) # Type of property
85             [\s]+
86             ([^\s]*[^\n]*) # Value of property
87             $
88             /xms
89             );
90 0 0         if ($name) {
91 0           $properties{$name}{type} = $type;
92 0           $properties{$name}{value} = $value;
93             }
94 0 0         $debug && print STDERR Data::Dumper->Dump( [$name, $type, $value], [qw($name $type $value)] );
95             }
96 0 0         $debug && print STDERR Data::Dumper->Dump( [\%properties], [qw(%properties)] );
97 0           return \%properties;
98             }
99              
100             sub _svcadm {
101 0 0   0     $debug && warn( '_svcadm ' . join( ',', @_ ) );
102 0           my $self = shift;
103 0           my $svcadm_action = shift;
104 0           local $ENV{PATH} = '/bin:/usr/bin:/sbin:/usr/sbin';
105 0 0         open my $svc_adm, '-|', " svcadm $svcadm_action '$self->{FMRI}' 2>&1"
106             or croak 'Unable to administer SMF services';
107 0           close $svc_adm;
108             }
109              
110             =head2 new
111              
112             Create a new Service object. The parameter must be a valid, unique FMRI.
113              
114             =cut
115              
116             sub new {
117 0 0   0 1   $debug && warn( 'new ' . join( ',', @_ ) );
118 0           my $class = shift;
119 0           my $FMRI = shift;
120 0           my $service = bless {}, __PACKAGE__;
121 0           $service->{FMRI} = $FMRI;
122 0           return $service;
123             }
124              
125             =head2 status
126              
127             Get the current status of this service. Returns a string, 'disabled', 'enabled', 'offline'.
128              
129             =cut
130              
131             sub status {
132 0 0   0 1   $debug && warn( 'status ' . join( ',', @_ ) );
133 0           my $self = shift;
134 0           my ( $status, $date ) = $self->_svcs();
135 0 0         $debug
136             && warn( Data::Dumper->Dump( [ $status, $date ], [qw($status $date)] ) );
137 0           return $status;
138             }
139              
140             =head2 FMRI
141              
142             Returns the Fault Managed Resource Identifier for this service.
143              
144             =cut
145              
146             sub FMRI {
147 0 0   0 1   $debug && warn( 'FMRI ' . join( ',', @_ ) );
148 0           my $self = shift;
149 0           return $self->{FMRI};
150             }
151              
152             =head2 properties
153              
154             Returns all or some properties for this service.
155              
156             =cut
157              
158             sub properties {
159 0 0   0 1   $debug && warn( 'properties ' . join( ',', @_ ) );
160 0           my $self = shift;
161 0           my $properties = $self->_svcprop();
162 0           return %{$properties};
  0            
163             }
164              
165             =head2 property
166              
167             Returns the value of a single property of this service.
168              
169             =cut
170              
171             sub property {
172 0 0   0 1   $debug && warn( 'property ' . join( ',', @_ ) );
173 0           my $self = shift;
174 0           my $p = validate_pos( @_, { type => SCALAR } );
175 0           my ($property_name) = @{$p};
  0            
176              
177 0           my $properties = $self->_svcprop();
178 0 0         $debug && warn( Data::Dumper->Dump( [$properties], [qw($properties)] ) );
179 0 0         if ( defined $properties->{$property_name} ) {
180 0           return $properties->{$property_name}{value};
181             }
182             else {
183 0           carp "Unable to find property '$property_name' for " . $self->{FMRI};
184 0           return undef;
185             }
186             }
187              
188             =head2 property_type
189              
190             Returns the type of a single property of this service.
191              
192             =cut
193              
194             sub property_type {
195 0 0   0 1   $debug && warn( 'property_type ' . join( ',', @_ ) );
196 0           my $self = shift;
197 0           my $p = validate_pos( @_, { type => SCALAR } );
198 0           my ($property_name) = @{$p};
  0            
199              
200 0           my $properties = $self->_svcprop();
201 0 0         $debug && warn( Data::Dumper->Dump([$properties], [qw($properties)]) );
202 0 0         if ( defined $properties->{$property_name} ) {
203 0           return $properties->{$property_name}{type};
204             }
205             else {
206 0           carp "Unable to find property '$property_name' for " . $self->{FMRI};
207 0           return undef;
208             }
209             }
210              
211             =head2 disable
212              
213             This instructs SMF to disable the service permanently. To disable temporarily,
214             that is until the next time the server is rebooted, use the 'stop' method.
215              
216             =cut
217             sub disable {
218 0 0   0 1   $debug && warn( 'disable ' . join( ',', @_ ) );
219 0           my $self = shift;
220 0           return $self->_svcadm('disable');
221             }
222              
223             =head2 stop
224              
225             This instructs SMF to stop the service. It uses the -t flag to svcadm, so that
226             using this call will not prevent the service from starting the next time the
227             server reboots.
228              
229             =cut
230             sub stop {
231 0 0   0 1   $debug && warn( 'stop ' . join( ',', @_ ) );
232 0           my $self = shift;
233 0           return $self->_svcadm('disable -t');
234             }
235              
236             =head2 enable
237              
238             This instructs SMF to enable the service permanently. To enable temporarily,
239             that is until the next time the server is rebooted, see the 'start' method.
240              
241             =cut
242             sub enable {
243 0 0   0 1   $debug && warn( 'enable ' . join( ',', @_ ) );
244 0           my $self = shift;
245 0           return $self->_svcadm('enable');
246             }
247              
248             =head2 start
249              
250             This instructs SMF to start the service. This change is not made persistent
251             unless you use the 'enable' method.
252              
253             =cut
254             sub start {
255 0 0   0 1   $debug && warn( 'start ' . join( ',', @_ ) );
256 0           my $self = shift;
257 0           return $self->_svcadm('enable -t');
258             }
259              
260             =head2 refresh
261              
262             This instructs SMF to refresh the service. Needed whenever alterations are
263             made to a service's properties. It acts as the analogue of a SQL 'commit'.
264              
265             =cut
266             sub refresh {
267 0 0   0 1   $debug && warn( 'refresh ' . join( ',', @_ ) );
268 0           my $self = shift;
269 0           return $self->_svcadm('refresh');
270             }
271              
272             =head2 clear
273              
274             This instructs SMF to clear the service's state, that is, to remove the
275             'failed' marker from it. This is needed prior to starting a failed service.
276              
277             =cut
278             sub clear {
279 0 0   0 1   $debug && warn( 'clear ' . join( ',', @_ ) );
280 0           my $self = shift;
281 0           return $self->_svcadm('clear');
282             }
283              
284             =head2 mark
285              
286             This instructs SMF to mark the service as failed.
287              
288             =cut
289             sub mark {
290 0 0   0 1   $debug && warn( 'mark ' . join( ',', @_ ) );
291 0           my $self = shift;
292 0           return $self->_svcadm('mark');
293             }
294              
295             =head1 AUTHOR
296              
297             Brad Macpherson, C<< >>
298              
299             =head1 BUGS
300              
301             Please report any bugs or feature requests to C, or through
302             the web interface at L. I will be notified, and then you'll
303             automatically be notified of progress on your bug as I make changes.
304              
305              
306              
307              
308             =head1 SUPPORT
309              
310             You can find documentation for this module with the perldoc command.
311              
312             perldoc Solaris::SMF::Service
313              
314              
315             You can also look for information at:
316              
317             =over 4
318              
319             =item * RT: CPAN's request tracker
320              
321             L
322              
323             =item * AnnoCPAN: Annotated CPAN documentation
324              
325             L
326              
327             =item * CPAN Ratings
328              
329             L
330              
331             =item * Search CPAN
332              
333             L
334              
335             =back
336              
337              
338             =head1 ACKNOWLEDGEMENTS
339              
340              
341             =head1 COPYRIGHT & LICENCE
342              
343             Copyright 2009 Brad Macpherson.
344              
345             This program is free software; you can redistribute it and/or modify it
346             under the terms of either: the GNU General Public Licence as published
347             by the Free Software Foundation; or the Artistic Licence.
348              
349             See http://dev.perl.org/licenses/ for more information.
350              
351              
352             =cut
353              
354             1; # End of Solaris::SMF::Service