File Coverage

blib/lib/Svsh.pm
Criterion Covered Total %
statement 3 42 7.1
branch 0 12 0.0
condition 0 17 0.0
subroutine 1 5 20.0
pod 2 2 100.0
total 6 78 7.6


line stmt bran cond sub pod time code
1             package Svsh;
2              
3             # ABSTRACT: Process supervision shell for daemontools/perp/s6/runit
4              
5             our $VERSION = "1.002000";
6             $VERSION = eval $VERSION;
7              
8 1     1   18808 use Moo::Role;
  1         218514  
  1         7  
9              
10             =head1 NAME
11              
12             Svsh - Process supervision shell for daemontools/perp/s6/runit (base class)
13              
14             =head1 SYNOPSIS
15              
16             package Svsh::SomeSupervisor;
17              
18             use Moo;
19             use namespace::clean;
20              
21             with 'Svsh';
22              
23             # implement required methods
24              
25             =head1 DESCRIPTION
26              
27             C is a shell for process supervision suites of the C family,
28             including C, C and C. Refer to L for documentation of
29             the shell itself. This file documents the base class for Svsh adapter classes.
30              
31             =head1 ATTRIBUTES
32              
33             =head2 basedir
34              
35             I.
36              
37             The base directory from which the process supervisor is managing services.
38              
39             =cut
40              
41             has 'basedir' => (
42             is => 'ro',
43             required => 1
44             );
45              
46             =head2 bindir
47              
48             I.
49              
50             The directory where the process supervisor's tools are located. Any call to
51             the supervisor's tools will be prefixed with this path if provided. For usage
52             in case the tools are not in the running user's C environment variable.
53              
54             =cut
55              
56             has 'bindir' => (
57             is => 'ro'
58             );
59              
60             =head2 collapse
61              
62             I.
63              
64             A boolean indicating whether the L option should be
65             enabled.
66              
67             =cut
68              
69             has 'collapse' => (
70             is => 'rw',
71             default => sub { 0 }
72             );
73              
74             =head2 statuses
75              
76             I.
77              
78             A hash-ref of services and their statuses (this is automatically populated by
79             the respective C method in the adapter classes. For every service,
80             a hash-ref with C, C and C keys should exist.
81              
82             =cut
83              
84             has 'statuses' => (
85             is => 'ro',
86             writer => '_set_statuses'
87             );
88              
89             =head1 REQUIRED METHODS
90              
91             =head2 status()
92              
93             Finds all services managed by the supervisor, and populates
94             the L attribute.
95              
96             =head2 start( @services )
97              
98             Starts a list of services if they are down.
99              
100             =head2 stop( @services )
101              
102             Stops a list of services (should not restart them).
103              
104             =head2 restart( @services )
105              
106             Stops and starts a list of services. Generally, this is implemented
107             with a C signal to the services, but check with the specific
108             adapter class.
109              
110             =head2 signal( $signal, @services )
111              
112             Sends UNIX signal to a list of services.
113              
114             =head2 fg( $service )
115              
116             Finds the log file to which a service is writing, and displays it
117             on screen with the C command.
118              
119             =head1 WANTED METHODS
120              
121             These methods are not required by adapter classes. If they are not
122             implemented, they will be unavailable in the shell.
123              
124             =head2 rescan()
125              
126             Causes the supervisor to rescan the service directory to find
127             new or removed services.
128              
129             =head2 terminate()
130              
131             Terminates the supervisor. Should also terminate all running services.
132              
133             =cut
134              
135             requires qw/status start stop restart signal fg/;
136              
137             before [qw/start stop restart/] => sub {
138             $_[2]->{args} = [$_[0]->_expand_wildcards(@{$_[2]->{args}})];
139             };
140              
141             before signal => sub {
142             my ($signal, @svcs) = @{$_[2]->{args}};
143             $_[2]->{args} = [$signal, $_[0]->_expand_wildcards(@svcs)];
144             };
145              
146             around 'status' => sub {
147             my ($orig, $self) = (shift, shift);
148             $self->_set_statuses($orig->($self, @_));
149             return $self->statuses;
150             };
151              
152             =head1 METHODS
153              
154             =head2 run_cmd( $cmd, [ @args ] )
155              
156             Runs a shell command with zero or more arguments and returns its
157             output. If the C attribute is set, and the C<$cmd> is one
158             of the supervision suite's library of tools, C<$cmd> will be prefixed
159             with C.
160              
161             =cut
162              
163             sub run_cmd {
164 0     0 1   my ($self, $cmd, @args) = @_;
165              
166 0           my $options = {};
167              
168 0 0 0       $cmd = $self->bindir . '/' . $cmd
169             if $self->bindir && $cmd =~ m/^(perp|s6|sv)/;
170              
171 0 0 0       if (scalar @args && ref $args[-1]) {
172 0           $options = pop @args;
173             }
174              
175 0 0         if ($options->{as_system}) {
176 0           system($cmd, @args);
177             } else {
178 0           $cmd = join(' ', $cmd, @args);
179 0           return qx/$cmd 2>&1/;
180             }
181             }
182              
183             =head2 find_logfile( $pid )
184              
185             Finds the log file into which a logging program is currently
186             writing to. C<$pid> is the process ID of the logging program.
187             Currently, C, C, C and C
188             are supported.
189              
190             Returns C if the file is not found.
191              
192             =cut
193              
194             sub find_logfile {
195 0     0 1   my ($self, $pid) = @_;
196              
197 0   0       my $exe = readlink("/proc/$pid/exe")
198             || return;
199              
200 0           my $file;
201              
202 0 0 0       if ($exe =~ m/tinylog/ || $exe =~ m/s6-log/ || $exe =~ m/svlogd/ || $exe =~ m/multilog/) {
      0        
      0        
203             # look for a link to a /current file under /proc/$pid/fd
204 0           opendir my $dir, "/proc/$pid/fd";
205 0           ($file) = grep { m!/current$! } map { readlink("/proc/$pid/fd/$_") } grep { !/^\.\.?$/ } readdir $dir;
  0            
  0            
  0            
206 0           closedir $dir;
207             }
208              
209 0           return $file;
210             }
211              
212             ######################################################################
213             # _expand_wildcards( @services )
214             # goes over a list of services, possibly (but not necessarily)
215             # with wildcards, and returns a new list with all services
216             # that match. For example, if @services = ('sv1', 'sv2', 'worker*'),
217             # and the services worker-1 and worker-2 exist, then the
218             # method will return ('sv1', 'sv2', 'worker-1', 'worker-2')
219             ######################################################################
220              
221             sub _expand_wildcards {
222 0     0     my $self = shift;
223              
224 0           my %services;
225 0           foreach (@_) {
226 0 0         if (m/\*/) {
227             # this is a wildcard, find all services that match it
228 0           my $regex = $_; $regex =~ s/\*/.*/; $regex = qr/^$regex$/;
  0            
  0            
229 0           foreach my $sv (grep { m/$regex/ } keys %{$self->statuses}) {
  0            
  0            
230 0           $services{$sv} = 1;
231             }
232             } else {
233 0           $services{$_} = 1;
234             }
235             }
236              
237 0           return keys %services;
238             }
239              
240             #########################################################
241             # _service_dirs()
242             # returns a list of all service directories inside the
243             # base directory
244             #########################################################
245              
246             sub _service_dirs {
247 0     0     my $basedir = shift->basedir;
248              
249 0           opendir(my $dh, $basedir);
250 0 0         my @dirs = grep { !/^\./ && -d "$basedir/$_" } readdir $dh;
  0            
251 0           closedir $dh;
252              
253 0           return sort @dirs;
254             }
255              
256             =head1 BUGS AND LIMITATIONS
257              
258             No bugs have been reported.
259              
260             Please report any bugs or feature requests to
261             C, or through the web interface at
262             L.
263              
264             =head1 SUPPORT
265              
266             You can find documentation for this module with the perldoc command.
267              
268             perldoc Svsh
269              
270             You can also look for information at:
271              
272             =over 4
273            
274             =item * RT: CPAN's request tracker
275            
276             L
277            
278             =item * AnnoCPAN: Annotated CPAN documentation
279            
280             L
281            
282             =item * CPAN Ratings
283            
284             L
285            
286             =item * Search CPAN
287            
288             L
289            
290             =back
291              
292             =head1 AUTHOR
293              
294             Ido Perlmuter
295              
296             =head1 LICENSE AND COPYRIGHT
297              
298             Copyright (c) 2015, Ido Perlmuter C<< ido at ido50 dot net >>.
299              
300             This module is free software; you can redistribute it and/or
301             modify it under the same terms as Perl itself, either version
302             5.8.1 or any later version. See L
303             and L.
304              
305             The full text of the license can be found in the
306             LICENSE file included with this module.
307              
308             =head1 DISCLAIMER OF WARRANTY
309              
310             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
311             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
312             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
313             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
314             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
315             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
316             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
317             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
318             NECESSARY SERVICING, REPAIR, OR CORRECTION.
319              
320             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
321             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
322             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
323             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
324             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
325             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
326             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
327             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
328             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
329             SUCH DAMAGES.
330              
331             =cut
332              
333             1;
334             __END__