Update cluster_cron.pl
This commit is contained in:
parent
85bd4a755f
commit
8c869e0fc8
1 changed files with 143 additions and 71 deletions
214
cluster_cron.pl
214
cluster_cron.pl
|
@ -2,102 +2,123 @@
|
|||
use warnings;
|
||||
use strict;
|
||||
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
|
||||
my ($electiondir, $cronfile, $sharedcronfile) = @_;
|
||||
my ($mode, $user, $shareddir, $spooldir) = @_;
|
||||
|
||||
unless (-d $electiondir) {
|
||||
mkdir $electiondir;
|
||||
# Set some defaults if we didn't get them
|
||||
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;
|
||||
|
||||
# We also need to know the time
|
||||
my $time = time;
|
||||
|
||||
# Create directories
|
||||
unless (-d $sharedcrondir) {
|
||||
mkdir $sharedcrondir or die "Can not create shared directory: $!";
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Get the nodes in the cluster
|
||||
sub get_nodes {
|
||||
# Our data type is a hash with the following fields
|
||||
# name, time, numeric
|
||||
my @nodes = ();
|
||||
my @files = <$electiondir/*>;
|
||||
foreach my $filename (@files) {
|
||||
my $node = {};
|
||||
open(FILE, "<$filename") or die "Could not open file: $!";
|
||||
$filename =~ s/^$electiondir\///;
|
||||
$node->{'name'} = $filename;
|
||||
my $content = <FILE>;
|
||||
chomp $content;
|
||||
$node->{'time'} = $content;
|
||||
$node->{'numeric'} = get_numeric($filename);
|
||||
close FILE;
|
||||
push @nodes, $node;
|
||||
}
|
||||
return @nodes;
|
||||
|
||||
# Our data type is a hash with the following fields
|
||||
# name, time, numeric
|
||||
my @nodes = ();
|
||||
my @files = <$electiondir/*>;
|
||||
foreach my $filename (@files) {
|
||||
my $node = {};
|
||||
open(FILE, "<$filename") or die "Could not open file: $!";
|
||||
$filename =~ s/^$electiondir\///;
|
||||
$node->{'name'} = $filename;
|
||||
my $content = <FILE>;
|
||||
chomp $content;
|
||||
$node->{'time'} = $content;
|
||||
$node->{'numeric'} = get_numeric($filename);
|
||||
close FILE;
|
||||
push @nodes, $node;
|
||||
}
|
||||
return @nodes;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
# Simply write a unix timestamp to a file with our name on it
|
||||
sub write_timestamp {
|
||||
open(FILE,"+>$electiondir/$hostname");
|
||||
print FILE $time;
|
||||
close FILE;
|
||||
open(FILE,"+>$electiondir/$hostname");
|
||||
print FILE $time;
|
||||
close FILE;
|
||||
|
||||
}
|
||||
|
||||
# Lets see if we are the active node
|
||||
sub is_active {
|
||||
|
||||
my @nodes = @_;
|
||||
my @nodes = @_;
|
||||
|
||||
# Assume you are active
|
||||
my $state = 1;
|
||||
# Loop all nodes
|
||||
foreach my $node (@nodes) {
|
||||
# Dont do anything if this is the node
|
||||
unless ($node eq $node->{'name'}) {
|
||||
# If it has been active in the last 120 seconds it is eligable
|
||||
my $diff = $time - $node->{'time'};
|
||||
if( $diff < 120 ) {
|
||||
# Go to passive mode if the numeric of that host is less than that of this host
|
||||
if( get_numeric($hostname) > $node->{'numeric'} ) {
|
||||
$state = 0 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $state;
|
||||
# Assume you are active
|
||||
my $state = 1;
|
||||
# Loop all nodes
|
||||
foreach my $node (@nodes) {
|
||||
# Dont do anything if this is the node
|
||||
unless ($node eq $node->{'name'}) {
|
||||
# If it has been active in the last 120 seconds it is eligable
|
||||
my $diff = $time - $node->{'time'};
|
||||
if( $diff < 120 ) {
|
||||
# Go to passive mode if the numeric of that host is less than that of this host
|
||||
if( get_numeric($hostname) > $node->{'numeric'} ) {
|
||||
$state = 0 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $state;
|
||||
}
|
||||
|
||||
# Turn a hostname in to a decimal number used for comparison, lowest numer gets to be active if it is working
|
||||
sub get_numeric {
|
||||
my ($host) = @_;
|
||||
my @ascii = unpack 'C*', $host;
|
||||
my $numeric = '';
|
||||
foreach my $val (@ascii) {
|
||||
$numeric .= $val;
|
||||
}
|
||||
return $numeric + 0;
|
||||
my ($host) = @_;
|
||||
my @ascii = unpack 'C*', $host;
|
||||
my $numeric = '';
|
||||
foreach my $val (@ascii) {
|
||||
$numeric .= $val;
|
||||
}
|
||||
return $numeric + 0;
|
||||
}
|
||||
|
||||
# But a # infront of any actime crontab entry
|
||||
sub comment_out {
|
||||
my ($infile, $outfile) = @_;
|
||||
open(INFILE,"<$infile");
|
||||
my $content = '';
|
||||
while(my $line = <INFILE>) {
|
||||
$line =~ s/(^(?!#))/#$1/g;
|
||||
$content .= $line;
|
||||
}
|
||||
|
||||
close INFILE;
|
||||
open(OUTFILE,"+>$outfile");
|
||||
print OUTFILE $content;
|
||||
close OUTFILE;
|
||||
my ($infile, $outfile) = @_;
|
||||
open(INFILE,"<$infile");
|
||||
my $content = '';
|
||||
while(my $line = <INFILE>) {
|
||||
$line =~ s/(^(?!#))/#$1/g;
|
||||
$content .= $line;
|
||||
}
|
||||
|
||||
close INFILE;
|
||||
open(OUTFILE,"+>$outfile");
|
||||
print OUTFILE $content;
|
||||
close OUTFILE;
|
||||
|
||||
}
|
||||
|
||||
|
@ -118,13 +139,64 @@ sub uncomment {
|
|||
|
||||
}
|
||||
|
||||
# Update timestamp
|
||||
write_timestamp;
|
||||
# If we are running in active/active mode
|
||||
if($mode) {
|
||||
unless (-d $electiondir) {
|
||||
mkdir $electiondir;
|
||||
}
|
||||
|
||||
# See if I am the one
|
||||
if (is_active(get_nodes) ){
|
||||
uncomment $sharedcronfile, $cronfile;
|
||||
# Update timestamp
|
||||
write_timestamp;
|
||||
|
||||
# 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…
Add table
Reference in a new issue