Update cluster_cron.pl

master
Mikael Nordin 8 years ago committed by GitHub
parent 85bd4a755f
commit 8c869e0fc8

@ -2,102 +2,123 @@
use warnings; use warnings;
use strict; use strict;
use Sys::Hostname; use Sys::Hostname;
use File::Compare;
use File::Copy;
# We need a common directory for our nodes to write and read state from plus a couple of cronfiles # We need a common directory for our nodes to write and read state from plus a couple of cronfiles
my ($electiondir, $cronfile, $sharedcronfile) = @_; my ($mode, $user, $shareddir, $spooldir) = @_;
unless (-d $electiondir) { # Set some defaults if we didn't get them
mkdir $electiondir; unless ($mode) {
# mode 0 = active/passive, mode 1 = active/active
$mode = 1;
}
unless ($user) {
$user = "www-data";
}
unless ($shareddir) {
$shareddir = "/var/lib/thruk";
}
unless ($spooldir) {
$spooldir = "/var/spool/cron/crontabs";
} }
# We need our name my $sharedcrondir = "$shareddir/crontab";
my $cronfile = "$spooldir/$user";
my $sharedcronfile = "$sharedcrondir/$user";
my $oldsharedcronfile = "$sharedcrondir/$user.old";
my $electiondir = "$sharedcrondir/election";
my $hostname = hostname; my $hostname = hostname;
# We also need to know the time
my $time = time; my $time = time;
# Create directories
unless (-d $sharedcrondir) {
mkdir $sharedcrondir or die "Can not create shared directory: $!";
}
# Get the nodes in the cluster # Get the nodes in the cluster
sub get_nodes { sub get_nodes {
# Our data type is a hash with the following fields # Our data type is a hash with the following fields
# name, time, numeric # name, time, numeric
my @nodes = (); my @nodes = ();
my @files = <$electiondir/*>; my @files = <$electiondir/*>;
foreach my $filename (@files) { foreach my $filename (@files) {
my $node = {}; my $node = {};
open(FILE, "<$filename") or die "Could not open file: $!"; open(FILE, "<$filename") or die "Could not open file: $!";
$filename =~ s/^$electiondir\///; $filename =~ s/^$electiondir\///;
$node->{'name'} = $filename; $node->{'name'} = $filename;
my $content = <FILE>; my $content = <FILE>;
chomp $content; chomp $content;
$node->{'time'} = $content; $node->{'time'} = $content;
$node->{'numeric'} = get_numeric($filename); $node->{'numeric'} = get_numeric($filename);
close FILE; close FILE;
push @nodes, $node; push @nodes, $node;
} }
return @nodes; return @nodes;
} }
# Simply write a unix timestamp to a file with our name on it # Simply write a unix timestamp to a file with our name on it
sub write_timestamp { sub write_timestamp {
open(FILE,"+>$electiondir/$hostname"); open(FILE,"+>$electiondir/$hostname");
print FILE $time; print FILE $time;
close FILE; close FILE;
} }
# Lets see if we are the active node # Lets see if we are the active node
sub is_active { sub is_active {
my @nodes = @_; my @nodes = @_;
# Assume you are active # Assume you are active
my $state = 1; my $state = 1;
# Loop all nodes # Loop all nodes
foreach my $node (@nodes) { foreach my $node (@nodes) {
# Dont do anything if this is the node # Dont do anything if this is the node
unless ($node eq $node->{'name'}) { unless ($node eq $node->{'name'}) {
# If it has been active in the last 120 seconds it is eligable # If it has been active in the last 120 seconds it is eligable
my $diff = $time - $node->{'time'}; my $diff = $time - $node->{'time'};
if( $diff < 120 ) { if( $diff < 120 ) {
# Go to passive mode if the numeric of that host is less than that of this host # Go to passive mode if the numeric of that host is less than that of this host
if( get_numeric($hostname) > $node->{'numeric'} ) { if( get_numeric($hostname) > $node->{'numeric'} ) {
$state = 0 ; $state = 0 ;
} }
} }
} }
} }
return $state; return $state;
} }
# Turn a hostname in to a decimal number used for comparison, lowest numer gets to be active if it is working # Turn a hostname in to a decimal number used for comparison, lowest numer gets to be active if it is working
sub get_numeric { sub get_numeric {
my ($host) = @_; my ($host) = @_;
my @ascii = unpack 'C*', $host; my @ascii = unpack 'C*', $host;
my $numeric = ''; my $numeric = '';
foreach my $val (@ascii) { foreach my $val (@ascii) {
$numeric .= $val; $numeric .= $val;
} }
return $numeric + 0; return $numeric + 0;
} }
# But a # infront of any actime crontab entry # But a # infront of any actime crontab entry
sub comment_out { sub comment_out {
my ($infile, $outfile) = @_; my ($infile, $outfile) = @_;
open(INFILE,"<$infile"); open(INFILE,"<$infile");
my $content = ''; my $content = '';
while(my $line = <INFILE>) { while(my $line = <INFILE>) {
$line =~ s/(^(?!#))/#$1/g; $line =~ s/(^(?!#))/#$1/g;
$content .= $line; $content .= $line;
} }
close INFILE; close INFILE;
open(OUTFILE,"+>$outfile"); open(OUTFILE,"+>$outfile");
print OUTFILE $content; print OUTFILE $content;
close OUTFILE; close OUTFILE;
} }
@ -118,13 +139,64 @@ sub uncomment {
} }
# Update timestamp # If we are running in active/active mode
write_timestamp; if($mode) {
unless (-d $electiondir) {
mkdir $electiondir;
}
# See if I am the one # Update timestamp
if (is_active(get_nodes) ){ write_timestamp;
uncomment $sharedcronfile, $cronfile;
# See if I am the one
if (is_active(get_nodes) ){
uncomment $sharedcronfile, $cronfile;
} else {
comment_out $cronfile, $sharedcronfile;
}
} else {
comment_out $cronfile, $sharedcronfile;
} }
# If we are running in actie/passive mode
else {
# If we don't have any cronjob on this host
unless (-e $cronfile) {
# If we have a cronjob on the shared drive
if (-e $sharedcronfile) {
copy($sharedcronfile, $cronfile) or die "Copy failed: $!";
copy($sharedcronfile, $oldsharedcronfile) or die "Copy failed: $!";
}
# Nothing to do, no cronjob on any host
exit;
}
# If there is no cronjob on the shared drive
unless (-e $sharedcronfile) {
# But we have a cronjob on this host
if (-e $cronfile) {
copy($cronfile, $sharedcronfile) or die "Copy failed: $!";
}
exit;
}
# Current cronfile and shared cronfile is not same
if(compare($cronfile, $sharedcronfile) != 0) {
# This means that the other node has changed the cron file
if(compare($cronfile, $oldsharedcronfile) == 0) {
copy($sharedcronfile, $cronfile) or die "Copy failed: $!";
copy($sharedcronfile, $oldsharedcronfile) or die "Copy failed: $!";
# All files are now the same
# This means that my node has changed the cron file
} else {
copy($cronfile, $sharedcronfile) or die "Copy failed: $!";
# The other node will now detect the difference and do the correct adjustment
}
}
}
exit;

Loading…
Cancel
Save