File reset-ip of Package dhcp

#! /usr/bin/perl

#
# Author: Kevin C. Miller <kevinm@andrew.cmu.edu>
# http://www.andrew.cmu.edu/~kevinm/dhcp/failover.html
#
# The copyright is with the author. We (SuSE) include this script
# with his permission.
#

# NOTE: you have to edit this script to make it functional for you.

## Reset IPs that are stuck in some weird state on the DHCP servers
## You can run it standalone, and it just reports statistics
##
## Or run with option '-reset' to reset many of the problem IPs
## Or run with option '-primary' to only reset problem IPs on the primary
##
## ** Note: You probably want to run -primary if you are in a low-free-IP 
##    situation. In this case -reset may enter a race condition and 
##    reset valid IPs on the secondary.

use strict;

my $PRIMARY = "/afs/andrew/usr/kevinm/dhcp1";
my $PRIMARY_IP = '128.2.4.2';
my $SEC = "/afs/andrew/usr/kevinm/dhcp3";
my $SEC_IP = '128.2.32.38';

my $RESET = "/afs/andrew/usr/kevinm/bin/clearip";
my %curstate;
my %nextstate;

my ($TotalPrimary, $TotalSecondary) = (0,0);
my ($LeasesDiff, $LeasesEq) = (0,0);
open(FILE, $PRIMARY)
  || die "Cannot open primary $PRIMARY";
while(<FILE>) {
  next if ($_ =~ /^\#/);
  my @a = split(/\s+/, $_);
  $curstate{$a[0]} = $a[1];
  $nextstate{$a[0]} = $a[3];
  $TotalPrimary++;
}
close(FILE);

my @ResetPrimary;
my @ResetSecondary;
open(FILE, $SEC)
  || die "Cannot open secondary $SEC";
while(<FILE>) {
  next if ($_ =~ /^\#/);
  my @a = split(/\s+/, $_);
  my ($key, $cur, $next) = ($a[0], $a[1], $a[3]);
  $TotalSecondary++;
    if ($curstate{$key} ne $cur &&  
       ($nextstate{$key} ne $next ||
       $nextstate{$key} eq '' && $next eq '')) {
    ## There is some difference
    $LeasesDiff++;
    if ($curstate{$key} eq 'active' &&
        $nextstate{$key} eq 'expired' && 
        $cur eq 'expired' && $next eq 'free') {
      # Reset both
      push(@ResetPrimary, $key);
      push(@ResetSecondary, $key);
    }elsif($curstate{$key} eq 'expired' &&
           $nextstate{$key} eq 'free' &&
           $cur eq 'active' &&
           $next eq 'expired') {
      # Reset both
      push(@ResetPrimary, $key);
      push(@ResetSecondary, $key);
    }elsif( ($curstate{$key} eq 'backup' &&
             $cur eq 'free') ) {
      # Reset both
      push(@ResetPrimary, $key);
      push(@ResetSecondary, $key);
    }elsif($curstate{$key} eq 'expired' &&
           $nextstate{$key} eq 'free' &&
           $cur eq 'free') {
      # Reset both
      push(@ResetPrimary, $key);
      push(@ResetSecondary, $key);
    }elsif(!defined $curstate{$key} && 
           !defined $nextstate{$key}) {
      push(@ResetSecondary, $key);
    }
      
    # There are other tests that could be made (primary
    # thinks the lease is 'backup', secondary doesn't know
    # about it).. etc. 
  }else{
    # No difference in state
    $LeasesEq++;
  }
  delete $curstate{$key};
  delete $nextstate{$key};
}

# Go through all the IPs on the primary that aren't defined
# on the secondary at all.
foreach my $key (keys %curstate) {
  if ($curstate{$key} eq 'backup') {
    push(@ResetPrimary, $key);
  }
}

if ($ARGV[0] eq '-reset') {
  reset_ips($PRIMARY_IP, $SEC_IP, \@ResetPrimary,
	    \@ResetSecondary, $RESET);
}elsif($ARGV[0] eq '-primary') {
  reset_ips($PRIMARY_IP, '', \@ResetPrimary, [], $RESET);
}
         
# Print statistics
print "Leases compared. Primary: $TotalPrimary   Secondary: $TotalSecondary\n";
print "  Different: $LeasesDiff    Equal: $LeasesEq\n";
print "  (Different+Equal may not add up to Primary, due to \n";
print "   missing entries in the leases file.)\n";

exit(1);
  
## ***********************************************************************
# Arguments:
#  - IP Address of primary DHCP server
#  - IP Address of secondary DHCP server
#  - Reference to an array of IPs to reset on the primary
#  - Reference to an array of IPs to reset on the secondary
#  - Reset script
sub reset_ips {
  my ($PrimaryIP, $SecIP, $rResetPrimary, $rResetSec, $Prog) = @_;

  foreach my $IP (@$rResetPrimary) {
    print "Resetting $IP on $PrimaryIP\n";
    `$Prog $IP $PrimaryIP`;
  }
  foreach my $IP (@$rResetSec) {
    print "Resetting $IP on $SecIP\n";
    `$Prog $IP $SecIP`;
  } 
}