File Coverage

lib/Rex/Commands/Service.pm
Criterion Covered Total %
statement 26 129 20.1
branch 0 76 0.0
condition 0 6 0.0
subroutine 9 14 64.2
pod 2 3 66.6
total 37 228 16.2


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             =head1 NAME
6              
7             Rex::Commands::Service - Manage System Services
8              
9             =head1 DESCRIPTION
10              
11             With this module you can manage Linux services.
12              
13             =head1 SYNOPSIS
14              
15             use Rex::Commands::Service
16              
17             service apache2 => "start";
18              
19             service apache2 => "stop";
20              
21             service apache2 => "restart";
22              
23             service apache2 => "status";
24              
25             service apache2 => "reload";
26              
27             service apache2 => "ensure", "started";
28              
29             service apache2 => "ensure", "stopped";
30              
31             =head1 EXPORTED FUNCTIONS
32              
33             =cut
34              
35             package Rex::Commands::Service;
36              
37 32     32   540 use v5.12.5;
  32         175  
38 32     32   243 use warnings;
  32         128  
  32         1790  
39              
40             our $VERSION = '1.14.2.2'; # TRIAL VERSION
41              
42             require Rex::Exporter;
43              
44 32     32   258 use vars qw(@EXPORT);
  32         87  
  32         1622  
45 32     32   269 use base qw(Rex::Exporter);
  32         94  
  32         2605  
46              
47 32     32   430 use Rex::Service;
  32         118  
  32         496  
48 32     32   1028 use Rex::Logger;
  32         91  
  32         154  
49 32     32   677 use Rex::Config;
  32         119  
  32         1764  
50 32     32   264 use Rex::Hook;
  32         111  
  32         1890  
51 32     32   244 use Carp;
  32         85  
  32         46491  
52              
53             @EXPORT = qw(service service_provider_for);
54              
55             =head2 service($service, $action, [$option])
56              
57             The service function accepts 2 parameters. The first is the service name and the second the action you want to perform.
58              
59             =over 4
60              
61             =item starting a service
62              
63             task "start-service", "server01", sub {
64             service apache2 => "start";
65             };
66              
67             =item stopping a service
68              
69             task "stop-service", "server01", sub {
70             service apache2 => "stop";
71             };
72              
73             =item restarting a service
74              
75             task "restart-service", "server01", sub {
76             service apache2 => "restart";
77             };
78              
79              
80             =item checking status of a service
81              
82             task "status-service", "server01", sub {
83             if( service apache2 => "status" ) {
84             say "Apache2 is running";
85             }
86             else {
87             say "Apache2 is not running";
88             }
89             };
90              
91             =item reloading a service
92              
93             task "reload-service", "server01", sub {
94             service apache2 => "reload";
95             };
96              
97              
98             =item ensure that a service will started at boot time
99              
100             task "prepare", sub {
101             service "apache2",
102             ensure => "started";
103             };
104              
105             =item ensure that a service will NOT be started.
106              
107             task "prepare", sub {
108             service "apache2",
109             ensure => "stopped";
110             };
111              
112              
113             If you need to define a custom command for start, stop, restart, reload or status you can do this with the corresponding options.
114              
115             task "prepare", sub {
116             service "apache2",
117             ensure => "started",
118             start => "/usr/local/bin/httpd -f /etc/my/httpd.conf",
119             stop => "killall httpd",
120             status => "ps -efww | grep httpd",
121             restart => "killall httpd && /usr/local/bin/httpd -f /etc/my/httpd.conf",
122             reload => "killall httpd && /usr/local/bin/httpd -f /etc/my/httpd.conf";
123             };
124              
125             This function supports the following L:
126              
127             =over 4
128              
129             =item before_${action}
130              
131             For example: C, C, C
132              
133             This gets executed right before the given service action. All original parameters are passed to it.
134              
135             =item after_${action}
136              
137             For example: C, C, C
138              
139             This gets executed right after the given service action. All original parameters, and any returned results are passed to it.
140              
141             =back
142              
143             =back
144              
145             =cut
146              
147             sub service {
148 0     0 1   my ( $services, $action, @_options ) = @_;
149              
150 0           my $opt_ref = {};
151 0 0         if ( scalar @_options >= 1 ) {
152 0           $opt_ref = { $action, @_options };
153             }
154             else {
155 0           $opt_ref = { ensure => $action, no_boot => 1 };
156             }
157              
158             # $opt_ref = {
159             # ensure => "start(ed)",
160             # no_boot => 1,
161             # ... => ...,
162             # }
163             #######
164              
165 0 0         if (wantarray) {
166              
167             # func-ref zurueckgeben
168             return sub {
169 0     0     service( $services, $action );
170 0           };
171              
172             }
173              
174 0           my $is_multiple = 1;
175 0 0         unless ( ref($services) ) {
176 0           $services = [$services];
177 0           $is_multiple = 0;
178             }
179              
180 0           my $srvc = Rex::Service->get;
181              
182 0           my $changed = 0;
183 0           my $return = 1;
184 0           for my $res_service (@$services) {
185              
186 0           my $service = $res_service;
187 0 0         if ( exists $opt_ref->{name} ) {
188 0           $service = $opt_ref->{name};
189             }
190              
191 0           my $notify = Rex::get_current_connection()->{notify};
192             $notify->add(
193             type => "service",
194             name => $service,
195             postpone => 1,
196             options => {},
197             cb => sub {
198 0     0     my ($option) = shift;
199 0           Rex::Logger::debug("Restarting notified service: $service");
200 0           service( $service => "restart" );
201             }
202 0           );
203              
204             #### check and run before_$action hook
205 0           Rex::Hook::run_hook( service => "before_$action", @_ );
206             ##############################
207              
208 0 0         if ( scalar @_ == 2 ) {
209 0           return old_service( $service, $action );
210             }
211              
212             ####### new service code
213              
214             Rex::get_current_connection()->{reporter}
215 0           ->report_resource_start( type => "service", name => $res_service );
216              
217 0           my $b_status = $srvc->status($service);
218 0           my $return;
219              
220 0 0         if ( $opt_ref->{ensure} =~ m/^(start|run|enable)/ ) {
    0          
221 0 0 0       if ( exists $opt_ref->{no_boot} && $opt_ref->{no_boot} ) {
222 0           $return = $srvc->start( $service, $opt_ref );
223             }
224             else {
225 0           $return = $srvc->ensure( $service, $opt_ref );
226             }
227             }
228             elsif ( $opt_ref->{ensure} =~ m/^(stop|disable)/ ) {
229 0 0 0       if ( exists $opt_ref->{no_boot} && $opt_ref->{no_boot} ) {
230 0           $return = $srvc->stop( $service, $opt_ref );
231             }
232             else {
233 0           $return = $srvc->ensure( $service, $opt_ref );
234             }
235             }
236             else {
237 0           Rex::Logger::info( "$opt_ref->{ensure} unknown ensure value.", "error" );
238 0           confess "$opt_ref->{ensure} unknown ensure value.";
239             }
240              
241 0           my $a_status = $srvc->status( $service, $opt_ref );
242              
243 0           $changed = 0;
244 0 0         if ( $a_status != $b_status ) {
245 0           $changed = 1;
246             }
247              
248             #### check and run after_$action hook
249             Rex::Hook::run_hook(
250 0           service => "after_$action",
251             @_, { changed => $changed, ret => $return }
252             );
253             ##############################
254              
255 0 0         if ($changed) {
256             Rex::get_current_connection()->{reporter}->report(
257 0           changed => 1,
258             message => "Service $service changed status to $opt_ref->{ensure}."
259             );
260             }
261             else {
262 0           Rex::get_current_connection()->{reporter}->report( changed => 0, );
263             }
264              
265             Rex::get_current_connection()->{reporter}
266 0           ->report_resource_end( type => "service", name => $res_service );
267             }
268              
269             }
270              
271             sub old_service {
272              
273 0     0 0   my ( $service, $action, $options ) = @_;
274              
275 0           my $srvc = Rex::Service->get;
276 0           my $changed;
277 0           my $is_multiple = 0;
278 0           my $return;
279              
280             Rex::get_current_connection()->{reporter}
281 0           ->report_resource_start( type => "service", name => $service );
282              
283 0 0         if ( $action eq "start" ) {
    0          
    0          
    0          
    0          
    0          
284              
285 0 0         unless ( $srvc->status($service) ) {
286 0           $changed = 1;
287 0 0         if ( $srvc->start($service) ) {
288 0           Rex::Logger::info("Service $service started.");
289 0 0         $return = 1 if !$is_multiple;
290             }
291             else {
292 0           Rex::Logger::info( "Error starting $service.", "warn" );
293 0 0         $return = 0 if !$is_multiple;
294             }
295             }
296              
297             }
298              
299             elsif ( $action eq "restart" ) {
300 0           $changed = 1;
301              
302 0 0         if ( $srvc->restart($service) ) {
303 0           Rex::Logger::info("Service $service restarted.");
304 0 0         $return = 1 if !$is_multiple;
305             }
306             else {
307 0           Rex::Logger::info( "Error restarting $service.", "warn" );
308 0 0         $return = 0 if !$is_multiple;
309             }
310              
311             }
312              
313             elsif ( $action eq "stop" ) {
314              
315 0 0         if ( $srvc->status($service) ) { # it runs
316 0           $changed = 1;
317 0 0         if ( $srvc->stop($service) ) {
318 0           Rex::Logger::info("Service $service stopped.");
319 0 0         $return = 1 if !$is_multiple;
320             }
321             else {
322 0           Rex::Logger::info( "Error stopping $service.", "warn" );
323 0 0         $return = 0 if !$is_multiple;
324             }
325             }
326              
327             }
328              
329             elsif ( $action eq "reload" ) {
330 0           $changed = 1;
331 0 0         if ( $srvc->reload($service) ) {
332 0           Rex::Logger::info("Service $service is reloaded.");
333 0 0         $return = 1 if !$is_multiple;
334             }
335             else {
336 0           Rex::Logger::info( "Error $service does not support reload", "warn" );
337 0 0         $return = 0 if !$is_multiple;
338             }
339              
340             }
341              
342             elsif ( $action eq "status" ) {
343              
344 0           $changed = 100;
345 0 0         if ( $srvc->status($service) ) {
346 0           Rex::Logger::info("Service $service is running.");
347 0 0         $return = 1 if !$is_multiple;
348             }
349             else {
350 0           Rex::Logger::info("$service is stopped");
351 0 0         $return = 0 if !$is_multiple;
352             }
353              
354             }
355              
356             elsif ( $action eq "ensure" ) {
357              
358 0 0         if ( $srvc->ensure( $service, { ensure => $options } ) ) {
359 0           $changed = 0;
360 0 0         $return = 1 if !$is_multiple;
361             }
362             else {
363 0 0         $return = 0 if !$is_multiple;
364 0           Rex::Logger::info("Error ensuring $service to $options");
365             }
366             }
367              
368             else {
369 0           Rex::Logger::info("Executing action $action on $service.");
370 0           $srvc->action( $service, $action );
371 0           $changed = 100;
372             }
373              
374 0 0         if ($changed) {
375             Rex::get_current_connection()->{reporter}
376 0           ->report( changed => $changed, message => "Service executed $action." );
377             }
378             else {
379 0           Rex::get_current_connection()->{reporter}->report( changed => 0, );
380             }
381              
382             Rex::get_current_connection()->{reporter}
383 0           ->report_resource_end( type => "service", name => $service );
384              
385 0           return $return;
386             }
387              
388             =head2 service_provider_for $os => $type;
389              
390             To set another service provider as the default, use this function.
391              
392             user "root";
393              
394             group "db" => "db[01..10]";
395             service_provider_for SunOS => "svcadm";
396              
397             task "start", group => "db", sub {
398             service ssh => "restart";
399             };
400              
401             This example will restart the I service via svcadm (but only on SunOS, on other operating systems it will use the default).
402              
403             =cut
404              
405             sub service_provider_for {
406 0     0 1   my ( $os, $provider ) = @_;
407 0           Rex::Logger::debug("setting service provider for $os to $provider");
408 0           Rex::Config->set( "service_provider", { $os => $provider } );
409             }
410              
411             1;