File Coverage

lib/Rex/Cron/Base.pm
Criterion Covered Total %
statement 125 151 82.7
branch 25 42 59.5
condition 3 5 60.0
subroutine 21 24 87.5
pod 0 13 0.0
total 174 235 74.0


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             package Rex::Cron::Base;
6              
7 2     2   67540 use v5.12.5;
  2         18  
8 2     2   11 use warnings;
  2         4  
  2         91  
9              
10             our $VERSION = '1.14.2.2'; # TRIAL VERSION
11              
12 2     2   417 use Rex::Logger;
  2         7  
  2         53  
13 2     2   594 use Rex::Commands;
  2         6  
  2         16  
14 2     2   20 use Rex::Commands::File;
  2         4  
  2         18  
15 2     2   13 use Rex::Commands::Fs;
  2         5  
  2         14  
16 2     2   15 use Rex::Helper::Run;
  2         8  
  2         151  
17 2     2   23 use Data::Dumper;
  2         6  
  2         89  
18 2     2   13 use Rex::Helper::Path;
  2         7  
  2         3601  
19              
20             sub new {
21 2     2 0 1613 my $that = shift;
22 2   33     16 my $proto = ref($that) || $that;
23 2         6 my $self = {@_};
24              
25 2         6 bless( $self, $proto );
26              
27 2         16 return $self;
28             }
29              
30             sub list {
31 6     6 0 40 my ($self) = @_;
32 6         9 return @{ $self->{cron} };
  6         83  
33             }
34              
35             sub list_jobs {
36 4     4 0 10318 my ($self) = @_;
37 4         10 my @jobs = @{ $self->{cron} };
  4         14  
38             my @ret =
39 25         38 map { { line => $_->{line}, %{ $_->{cron} } } }
  25         143  
40 4         10 grep { $_->{type} eq "job" } @jobs;
  69         117  
41             }
42              
43             sub list_envs {
44 6     6 0 3835 my ($self) = @_;
45 6         9 my @jobs = @{ $self->{cron} };
  6         46  
46 6         16 my @ret = grep { $_->{type} eq "env" } @jobs;
  94         177  
47             }
48              
49             sub add {
50 4     4 0 25601 my ( $self, %config ) = @_;
51              
52 4         15 %config = $self->_create_defaults(%config);
53              
54             my $new_cron = sprintf(
55             "%s %s %s %s %s %s",
56             $config{"minute"}, $config{"hour"}, $config{"day_of_month"},
57 4         18 $config{"month"}, $config{"day_of_week"}, $config{"command"},
58             );
59              
60 4         7 my $dupe = grep { $_->{line} eq $new_cron } @{ $self->{cron} };
  62         95  
  4         9  
61 4 50       11 if ($dupe) {
62 0         0 Rex::Logger::debug("Job \"$new_cron\" already installed, skipping.");
63 0         0 return 0;
64             }
65              
66             push(
67 4         6 @{ $self->{cron} },
  4         15  
68             {
69             type => "job",
70             line => $new_cron,
71             cron => \%config,
72             }
73             );
74              
75 4         10 return 1;
76             }
77              
78             sub add_env {
79 2     2 0 44547 my ( $self, $name, $value ) = @_;
80              
81 2         4 my $env_index = 0;
82 2         4 my $exists = 0;
83 2         6 for my $env ( $self->list_envs ) {
84 7 50       19 if ( $env->{name} eq "$name" ) {
85 0 0       0 if ( $env->{value} ne "\"$value\"" ) {
86 0         0 Rex::Logger::debug("Environment variable changed : $name");
87 0         0 $self->delete_env($env_index);
88             }
89             else {
90 0         0 Rex::Logger::debug(
91             "Environment variable already exists with same value: $name=$value");
92 0         0 $exists = 1;
93             }
94             }
95              
96 7         12 $env_index++;
97             }
98              
99 2 50       9 if ( $exists == 0 ) {
100             unshift(
101 2         5 @{ $self->{cron} },
  2         17  
102             {
103             type => "env",
104             line => "$name=\"$value\"",
105             name => $name,
106             value => $value,
107             }
108             );
109             }
110             }
111              
112             sub delete_job {
113 2     2 0 11627 my ( $self, $num ) = @_;
114 2         7 my @jobs = $self->list_jobs;
115              
116 2         6 my $i = 0;
117 2         4 my $to_delete;
118 2         4 for my $j ( @{ $self->{cron} } ) {
  2         7  
119 23 100       45 if ( $j->{line} eq $jobs[$num]->{line} ) {
120 2         5 $to_delete = $i;
121 2         5 last;
122             }
123              
124 21         26 $i++;
125             }
126              
127 2 50       13 unless ( defined $to_delete ) {
128 0         0 die("Cron Entry $num not found.");
129             }
130              
131 2         8 $self->delete($to_delete);
132             }
133              
134             sub delete_env {
135 2     2 0 5818 my ( $self, $num ) = @_;
136              
137 2         5 my @jobs = $self->list_envs;
138              
139 2         6 my $i = 0;
140 2         4 my $to_delete;
141 2         5 for my $j ( @{ $self->{cron} } ) {
  2         6  
142 3 100       9 if ( $j->{line} eq $jobs[$num]->{line} ) {
143 2         5 $to_delete = $i;
144 2         7 last;
145             }
146              
147 1         3 $i++;
148             }
149              
150 2 50       30 unless ( defined $to_delete ) {
151 0         0 die("Cron Entry $num not found.");
152             }
153              
154 2         6 $self->delete($to_delete);
155             }
156              
157             sub delete {
158 6     6 0 48661 my ( $self, $num ) = @_;
159 6         11 splice( @{ $self->{cron} }, $num, 1 );
  6         27  
160             }
161              
162             # returns a filename where the new cron is written to
163             # after that the cronfile must be activated
164             sub write_cron {
165 1     1 0 16365 my ($self) = @_;
166              
167 1         8 my $rnd_file = get_tmp_file;
168              
169 1         5 my @lines = map { $_->{line} } @{ $self->{cron} };
  18         47  
  1         5  
170              
171 1         7 my $fh = file_write $rnd_file;
172 1         14 $fh->write( join( "\n", @lines ) . "\n" );
173 1         9 $fh->close;
174              
175 1         9 return $rnd_file;
176             }
177              
178             sub activate_user_cron {
179 0     0 0 0 my ( $self, $file, $user ) = @_;
180 0 0       0 $user = undef if $user eq &_whoami;
181              
182 0         0 my $command = 'crontab';
183 0 0       0 $command .= " -u $user" if defined $user;
184              
185 0         0 i_run "$command $file";
186 0         0 unlink $file;
187             }
188              
189             sub read_user_cron {
190 0     0 0 0 my ( $self, $user ) = @_;
191 0 0       0 $user = undef if $user eq &_whoami;
192              
193 0         0 my $command = 'crontab -l';
194 0 0       0 $command .= " -u $user" if defined $user;
195 0         0 $command .= ' 2> /dev/null';
196              
197 0         0 my @lines = i_run $command, fail_ok => 1;
198 0         0 $self->parse_cron(@lines);
199             }
200              
201             sub parse_cron {
202 2     2 0 20 my ( $self, @lines ) = @_;
203              
204 2         5 chomp @lines;
205              
206 2         5 my @cron;
207              
208 2         5 for my $line (@lines) {
209              
210             # comment
211 32 100       144 if ( $line =~ m/^#/ ) {
    50          
    100          
    50          
212 12         37 push(
213             @cron,
214             {
215             type => "comment",
216             line => $line,
217             }
218             );
219             }
220              
221             # empty line
222             elsif ( $line =~ m/^\s*$/ ) {
223 0         0 push(
224             @cron,
225             {
226             type => "empty",
227             line => $line,
228             }
229             );
230             }
231              
232             # job
233             elsif ( $line =~ m/^(@|\*|[0-9])/ ) {
234 14         69 my ( $min, $hour, $day, $month, $dow, $cmd ) = split( /\s+/, $line, 6 );
235 14         87 push(
236             @cron,
237             {
238             type => "job",
239             line => $line,
240             cron => {
241             minute => $min,
242             hour => $hour,
243             day_of_month => $day,
244             month => $month,
245             day_of_week => $dow,
246             command => $cmd,
247             },
248             }
249             );
250             }
251              
252             elsif ( $line =~ m/=/ ) {
253 6         22 my ( $name, $value ) = split( /=/, $line, 2 );
254 6         14 $name =~ s/^\s+//;
255 6         14 $name =~ s/\s+$//;
256 6         9 $value =~ s/^\s+//;
257 6         10 $value =~ s/\s+$//;
258              
259 6         27 push(
260             @cron,
261             {
262             type => "env",
263             line => $line,
264             name => $name,
265             value => $value,
266             }
267             );
268             }
269              
270             else {
271 0         0 Rex::Logger::debug("Error parsing cron line: $line");
272 0         0 next;
273             }
274              
275             }
276              
277 2         10 $self->{cron} = \@cron;
278 2         12 return @cron;
279             }
280              
281             sub _create_defaults {
282 4     4   10 my ( $self, %config ) = @_;
283              
284 4 100       12 $config{"minute"} = "*" unless defined $config{minute};
285 4 100       11 $config{"hour"} = "*" unless defined $config{hour};
286 4 100       10 $config{"day_of_month"} = "*" unless defined $config{day_of_month};
287 4 100       10 $config{"month"} = "*" unless defined $config{month};
288 4 100       9 $config{"day_of_week"} = "*" unless defined $config{day_of_week};
289 4   100     13 $config{"command"} ||= "false";
290              
291 4         20 return %config;
292             }
293              
294             sub _whoami {
295 0     0     return i_run q(perl -e 'print scalar getpwuid($<)');
296             }
297              
298             1;