The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

#
# (c) Jan Gehring <jan.gehring@gmail.com>
#
=head1 NAME
Rex::Commands::Cron - Simple Cron Management
=head1 DESCRIPTION
With this Module you can manage your cronjobs.
=head1 SYNOPSIS
use Rex::Commands::Cron;
cron add => "root", {
minute => '5',
hour => '*',
day_of_month => '*',
month => '*',
day_of_week => '*',
command => '/path/to/your/cronjob',
};
cron list => "root";
cron delete => "root", 3;
=head1 EXPORTED FUNCTIONS
=cut
use v5.12.5;
our $VERSION = '1.16.0'; # VERSION
require Rex::Exporter;
use vars qw(@EXPORT);
use Carp;
@EXPORT = qw(cron cron_entry);
=head2 cron_entry($name, %option)
Manage cron entries.
cron_entry "reload-httpd",
ensure => "present",
command => "/etc/init.d/httpd restart",
minute => "1,5",
hour => "11,23",
month => "1,5",
day_of_week => "1,3",
day_of_month => "1,3,5",
user => "root",
on_change => sub { say "cron added"; };
# remove an entry
cron_entry "reload-httpd",
ensure => "absent",
command => "/etc/init.d/httpd restart",
minute => "1,5",
hour => "11,23",
month => "1,5",
day_of_week => "1,3",
day_of_month => "1,3,5",
user => "root",
on_change => sub { say "cron removed."; };
=cut
sub cron_entry {
my ( $name, %option ) = @_;
$option{ensure} ||= "present";
confess "No 'user' given." if ( !exists $option{user} );
Rex::get_current_connection()->{reporter}
->report_resource_start( type => "cron_entry", name => $name );
my $changed = 0;
my $ensure = $option{ensure};
if ( $option{ensure} eq "present" ) {
Rex::Logger::debug("Creating new cron_entry: $name");
my $user = $option{user};
delete $option{user};
delete $option{ensure};
$changed = &cron( add => $user, \%option );
}
elsif ( $option{ensure} eq "absent" ) {
Rex::Logger::debug("Removing cron_entry: $name");
my $user = $option{user};
my $c = Rex::Cron->create();
%option = $c->_create_defaults(%option);
my @crons = &cron( list => $user );
my $i = 0;
my $cron_id;
for my $cron (@crons) {
if ( $cron->{minute} eq $option{minute}
&& $cron->{hour} eq $option{hour}
&& $cron->{month} eq $option{month}
&& $cron->{day_of_week} eq $option{day_of_week}
&& $cron->{day_of_month} eq $option{day_of_month}
&& $cron->{command} eq $option{command} )
{
# cron found
$cron_id = $i;
last;
}
$i++;
}
delete $option{user};
delete $option{ensure};
if ( defined $cron_id ) {
&cron( delete => $user, $cron_id );
$changed = 1;
}
else {
Rex::Logger::debug("Cron $name not found.");
Rex::Logger::debug( Dumper( \%option ) );
}
}
if ($changed) {
if ( exists $option{on_change} && ref $option{on_change} eq "CODE" ) {
$option{on_change}->( $name, %option );
}
Rex::get_current_connection()->{reporter}->report(
changed => 1,
message => "Resource cron_entry status changed to $ensure."
);
}
else {
Rex::get_current_connection()->{reporter}->report( changed => 0, );
}
Rex::get_current_connection()->{reporter}
->report_resource_end( type => "cron_entry", name => $name );
}
=head2 cron($action => $user, ...)
With this function you can manage cronjobs.
List cronjobs.
use Rex::Commands::Cron;
use Data::Dumper;
task "listcron", "server1", sub {
my @crons = cron list => "root";
print Dumper(\@crons);
};
Add a cronjob.
This example will add a cronjob running on minute 1, 5, 19 and 40. Every hour and every day.
use Rex::Commands::Cron;
use Data::Dumper;
task "addcron", "server1", sub {
cron add => "root", {
minute => "1,5,19,40",
command => '/path/to/your/cronjob',
};
};
This example will add a cronjob running on the 1st, 3rd and 5th day of January and May, but only when it's a Monday or Wednesday. On those days, the job will run when the hour is 11 or 23, and the minute is 1 or 5 (in other words at 11:01, 11:05, 23:01 and 23:05).
task "addcron", "server1", sub {
cron add => "root", {
minute => "1,5",
hour => "11,23",
month => "1,5",
day_of_week => "1,3",
day_of_month => "1,3,5",
command => '/path/to/your/cronjob',
};
};
Delete a cronjob.
This example will delete the 4th cronjob. Counting starts with zero (0).
task "delcron", "server1", sub {
cron delete => "root", 3;
};
Managing Environment Variables inside cron.
task "mycron", "server1", sub {
cron env => user => add => {
MYVAR => "foo",
};
cron env => user => delete => $index;
cron env => user => delete => 1;
cron env => user => "list";
};
=cut
sub cron {
my ( $action, $user, $config, @more ) = @_;
my $c = Rex::Cron->create();
$c->read_user_cron($user); # this must always be the first action
if ( $action eq "list" ) {
return $c->list_jobs;
}
elsif ( $action eq "add" ) {
if ( $c->add( %{$config} ) ) {
my $rnd_file = $c->write_cron;
$c->activate_user_cron( $rnd_file, $user );
return 1; # something changed
}
return 0; # nothing changed
}
elsif ( $action eq "delete" ) {
my $to_delete = $config;
$c->delete_job($to_delete);
my $rnd_file = $c->write_cron;
$c->activate_user_cron( $rnd_file, $user );
}
elsif ( $action eq "env" ) {
my $env_action = $config;
if ( $env_action eq "add" ) {
my $data = shift @more;
for my $key ( keys %{$data} ) {
$c->add_env( $key => $data->{$key}, );
}
my $rnd_file = $c->write_cron;
$c->activate_user_cron( $rnd_file, $user );
}
elsif ( $env_action eq "list" ) {
return $c->list_envs;
}
elsif ( $env_action eq "delete" ) {
my $num = shift @more;
$c->delete_env($num);
my $rnd_file = $c->write_cron;
$c->activate_user_cron( $rnd_file, $user );
}
}
}
1;