File Coverage

blib/lib/Daemon/Shutdown/Monitor/who.pm
Criterion Covered Total %
statement 21 64 32.8
branch 0 12 0.0
condition 0 8 0.0
subroutine 7 9 77.7
pod 2 2 100.0
total 30 95 31.5


line stmt bran cond sub pod time code
1             package Daemon::Shutdown::Monitor::who;
2              
3 1     1   1524 use warnings;
  1         3  
  1         31  
4 1     1   7 use strict;
  1         1  
  1         27  
5 1     1   5 use Params::Validate qw/:all/;
  1         3  
  1         198  
6 1     1   6 use IPC::Run;
  1         2  
  1         36  
7 1     1   6 use YAML::Any;
  1         2  
  1         9  
8 1     1   1363 use User;
  1         2  
  1         11  
9 1     1   25 use Log::Log4perl;
  1         2  
  1         24  
10              
11             =head1 NAME
12              
13             Daemon::Shutdown::Monitor::who - a who specific monitor
14              
15             =head1 SYNOPSIS
16              
17             Monitor users logged in with 'who'
18              
19             =head1 DESCRIPTION
20              
21             Tests if any users are logged in (using the 'who' command). When no users are logged in
22             the flag "trigger_pending" is set. If a further "trigger_time" seconds
23             pass and there are still no users logged in the trigger is sent back to the parent
24             process (return 1).
25              
26             =head1 METHODS
27              
28             =head2 new
29              
30             =over 2
31              
32             =item loop_sleep
33              
34             How long to sleep between each test
35              
36             Default: 60 (1 minute)
37              
38             =item trigger_time
39              
40             The time to wait after discovering that no users are currently logged in
41              
42             Default: 360 (10 minutes)
43              
44             =item user
45              
46             Monitor only a specific user.
47              
48             Default: undef
49              
50             =back
51              
52             =head3 Example configuration
53            
54             monitor:
55             who:
56             trigger_time: 1800
57             user: rclarke
58             loop_sleep: 1
59              
60             =cut
61              
62             sub new {
63 0     0 1   my $class = shift;
64 0           my %params = @_;
65              
66             # Validate the config file
67 0           %params = validate_with(
68             params => \%params,
69             spec => {
70             loop_sleep => {
71             regex => qr/^\d*$/,
72             default => 60,
73             },
74             trigger_time => {
75             regex => qr/^\d*$/,
76             default => 3600,
77             },
78             user => {
79             optional => 1,
80             regex => qr/^\w+$/,
81             },
82             },
83             );
84 0           my $self = {};
85 0           $self->{params} = \%params;
86              
87 0           $self->{trigger_pending} = 0;
88              
89 0           bless $self, $class;
90 0           my $logger = Log::Log4perl->get_logger();
91 0           $self->{logger} = $logger;
92 0           $logger->debug( "Monitor 'who' params:\n" . Dump( \%params ) );
93              
94 0           return $self;
95             }
96              
97             =head2 run
98              
99             Run the who Monitor
100              
101             =cut
102              
103             sub run {
104 0     0 1   my $self = shift;
105              
106 0           my $logger = $self->{logger};
107              
108 0           $logger->info( "Monitor started running: who" );
109              
110 0           my $users_count = 0;
111 0           my @cmd = ( 'who' );
112 0           $logger->debug( "Monitor 'who' CMD: " . join( ' ', @cmd ) );
113 0           my ( $in, $out, $err );
114 0 0         if ( not IPC::Run::run( \@cmd, \$in, \$out, \$err, IPC::Run::timeout( 10 ) ) ) {
115 0           $logger->warn( "Could not run '" . join( ' ', @cmd ) . "': $!" );
116             }
117 0 0         if ( $err ) {
118 0           $logger->error( "Monitor 'who' error: $err" );
119             }
120 0           my @lines = split( /\n/, $out );
121 0           my %users_logged_in;
122            
123 0           foreach my $line( @lines ){
124 0           my( $username ) = split( ' ' , $line );
125 0           $users_logged_in{$username}++;
126             }
127            
128 0 0         if( $self->{params}{user} ){
129 0   0       $users_count = $users_logged_in{$self->{params}{user}} || 0;
130             }else{
131 0           $users_count = scalar( keys( %users_logged_in ) );
132             }
133 0           $logger->debug( sprintf( "Monitor 'who' sees %u users logged in:\n%s", $users_count, $out ) );
134            
135 0 0         if ( $users_count == 0 ) {
136 0   0       $self->{trigger_pending} ||= time();
137 0 0 0       if ( $self->{trigger_pending}
138             and ( time() - $self->{trigger_pending} ) >= $self->{params}{trigger_time} )
139             {
140             # ... and the trigger was set, and time has run out: time to return!
141 0           my $time_since_trigger = time() - $self->{trigger_pending};
142 0           $logger->info( "Monitor 'who' trigger time reached after $time_since_trigger" );
143             # Reset the trigger_pending because otherwise if this was a suspend, and the computer comes
144             # up again hours/days later, it will immediately fall asleep again...
145 0           $self->{trigger_pending} = 0;
146 0           return 1;
147             }
148              
149 0           $logger->info( "Monitor 'who' found no users logged in: trigger pending." );
150             } else {
151 0 0         if ( $self->{trigger_pending} ) {
152 0           $logger->info( "Monitor 'who' trigger time being reset because users are now logged in" );
153             }
154              
155             # Conditions not met - reset the trigger incase it was previously set.
156 0           $self->{trigger_pending} = 0;
157             }
158 0           return 0;
159             }
160              
161             =head1 AUTHOR
162              
163             Robin Clarke, C
164              
165             =head1 LICENSE AND COPYRIGHT
166              
167             Copyright 2015 Robin Clarke.
168              
169             This program is free software; you can redistribute it and/or modify it
170             under the terms of either: the GNU General Public License as published
171             by the Free Software Foundation; or the Artistic License.
172              
173             See http://dev.perl.org/licenses/ for more information.
174              
175             =cut
176              
177             1; # End of Daemon::Shutdown::Monitor::who