Question about MySQL Replication Script

Domnick Eger deger at cobercafe.net
Mon May 17 22:41:53 CEST 2010


I tried to get this script working but it never seems to send data back to the hobbit server.


I ran the script in debug mode, and it seems to sending the correct information, but not sure why it not showing up on the hobbit.


[root at cs101 ext]# ./mysql-replication.pl
/home/hobbit/client/bin/bb 10.1.5.18 "status 10,1,5,39.replication green Mon May 17 20:14:22 2010 Mirroring OK

Node: node

master T1      at               mysql-bin.000302:949148896  (10.1.5.39)
slave  RUNNING                                              (10.1.5.44)
slave  ON TIME at               mysql-bin.000302:949164080  (10.1.5.44)
master T2      at               mysql-bin.000302:949179136  (10.1.5.39)
"





#!/usr/bin/perl -w
#
# mysql replication monitoring
# generic attempt

use strict;
#use Data::Dumper;
my $DEBUG       = 0;

$ENV{BBPROG}    = "bb-mysql-replication";
my $TESTNAME    = "mysqlrep";

my $BBHOME      = $ENV{BBHOME};
my $BB          = $ENV{BB};    # full path to the bin/bb util
my $BBDISP      = $ENV{BBDISP};       # IP of the BBDISPLAY server
my $BBVAR       = $ENV{BBVAR};
my $MACHINE     = $ENV{MACHINE}; # hostname, fqdn
my $COLOR       = "clear";     # global color for the test
my $MSG         = "";          # body of the message
my $HEAD        = ""; # first line of the message (has to be short, optional)
my $DATA        = "";          # data for NCV records (hobbit only)

if ($DEBUG == 1) {
        $BBHOME  = "/tmp" unless $BBHOME;
        $BBDISP  = "127.0.0.1" unless $BBDISP;
        $BBVAR   = "/tmp" unless $BBVAR;
        $MACHINE = "host.priv.com" unless $MACHINE;
}

# The Fine Manual :
sub clear;                     # sets status color to clear
sub green;                     # ~ to green
sub yellow;                    # ~ to yellow
sub red;                       # ~ to red
sub setcolor; # safely sets status color                       # setcolor("yellow")
sub head; # sets the first status line                     # head("foo OK")
sub msg; # adds text to the body of the status message    # msg("foo" [, "bar", ...])
sub data; # adds NCV-formatted data to the status message  # data(ds, value)
sub sendreport; # sends the report to the BB server              # sendreport()
sub resetreport; # wipes the report (head, body, data, color)     # resetreport()

# You can always use $MSG, $HEAD, $DATA and $COLOR directly.

########
# Put your code here
########

# What you need :
# on the remote masters and slaves, create:
# for mysql 4.x : grant replication client on *.* to 'user'@'monitorhost' identified by 'password';
#                 grant select on test.* to 'user'@'monitorhost' identified by 'password';
# for mysql 3.x : grant process on *.*   to 'user'@'monitorhost' identified by 'password';
#                 grant select on test.* to 'user'@'monitorhost' identified by 'password';
#

use DBI;

my $ERR;
my $legalERR = "[^a-zA-Z0-9.:,_ -]";
my ($status, $maitreSql, @slaves, $esclaveSql, $login, $pass, %auth, $node);
my ($positionMaitre_t1, $positionMaitre_t2, $positionEsclave, $slaveRunning, $error);
my $conffile="/usr2/hobbitlocal/etc/bb-mysql-replication.cfg";
my $OKOFFSET = 100;
readConfig();
foreach $node ( keys %auth ) {
        msg "Node: $node\n";
        green;                 # let's be optimit ;)

        $maitreSql  = $auth{$node}{master};
        @slaves     = keys %{ $auth{$node}{slaves} };
        $login      = $auth{$node}{user};
        $pass       = $auth{$node}{pass};
        $MACHINE    = $maitreSql;

        $positionMaitre_t1 = getSqlMasterStatus($maitreSql,$login,$pass,"test");
        if (not defined $positionMaitre_t1) {
                $ERR =~ s/$legalERR/ /go;
               msg(sprintf("master ERROR                    (%s) &red %s", $maitreSql, $ERR));
               head "mirroring FAILURE";
               sendreport;
               resetreport;
               next;
        }
        sleep 2;
        foreach $esclaveSql (@slaves) {
               ($positionEsclave, $slaveRunning,$error) = getSqlSlaveStatus($esclaveSql,$login,$pass,"test");
               next if not defined $positionEsclave;
               $auth{$node}{slaves}{$esclaveSql}{pos} = $positionEsclave;
               $auth{$node}{slaves}{$esclaveSql}{running} = $slaveRunning;
        }
        sleep 2;
        # on reprend la position sur le maître
        $positionMaitre_t2 = getSqlMasterStatus($maitreSql,$login,$pass,"test");
        if (not defined $positionMaitre_t2) {
               head "mirroring FAILURE";
                $ERR =~ s/$legalERR/ /go;
               msg(sprintf("master ERROR                    (%s) &red %s", $maitreSql, $ERR));
               sendreport;
               resetreport;
               next;
        }
        msg(sprintf("master T1      at % 40s  (%s)", $positionMaitre_t1, $maitreSql));

        foreach $esclaveSql (@slaves) {
               $positionEsclave = $auth{$node}{slaves}{$esclaveSql}{pos};
               $slaveRunning    = $auth{$node}{slaves}{$esclaveSql}{running};
               if (not defined $positionEsclave) {
                       $ERR =~ s/$legalERR/ /go;
                       msg "slave  ERROR                    ($esclaveSql) &red $ERR";
                       next;
               } elsif ($slaveRunning eq "Yes") {
                       msg "slave  RUNNING                                              ($esclaveSql)";
                       if ( ($positionMaitre_t1 le $positionEsclave) and
                            ($positionEsclave le $positionMaitre_t2) ) {
                               msg(sprintf("slave  ON TIME at % 40s  (%s)", $positionEsclave, $esclaveSql));
                       } else {
                               my($masterfile, $masteroffset, $slavefile, $slaveoffset);
                               ($masterfile, $masteroffset) = split(/:/, $positionMaitre_t1, 2);
                               ($slavefile, $slaveoffset) = split(/:/, $positionEsclave, 2);
                               msg(sprintf("slave  LATE    at % 40s  (%s) &yellow", $positionEsclave, $esclaveSql));
                               if($masterfile eq $slavefile) {
                                      if ($masteroffset - $slaveoffset < $OKOFFSET) {
                                              green;
                                      }
                                      else {
                                              yellow;
                                      }
                               }
                               else {
                                      $masterfile =~ s/.+\.(\d+)$/$1/;
                                      $slavefile  =~ s/.+\.(\d+)$/$1/;
                                      if($masterfile - $slavefile != 1) {
                                              yellow;
                                      }
                                      elsif($masteroffset < $OKOFFSET) {
                                              green;
                                      }
                                      else {
                                              yellow;
                                      }
                               }
                       }
               } else {
                       msg "slave  STOPPED                                              ($esclaveSql) &red";
                       red;
               }
               if($error ne "") {
                       red;
                       $error =~ s/$legalERR/ /go;
                       msg "slave  ERROR    $error";
               }
        }
        msg(sprintf("master T2      at % 40s  (%s)", $positionMaitre_t2, $maitreSql));

        if ($COLOR eq "green") {head "Mirroring OK"} else {head "Mirroring FAILURE"}
        sendreport;
        resetreport;
}

exit 0;

###############
###############


########################

# conffile has format :
# node;masterhost;slavehost1[,slavehost2,...];user;pass
# (so it works in multiple slave setups)
# example:
# authcluster;auth-sql01.priv.com;auth-sql02.priv.com;monitor;coUIc
# radius;rad-sql01.priv.com;rad-repsql01.priv.com,rad-backup01.priv.com;monitor;coUIc
# add comment lines with '#'
sub readConfig
{
        my ($node, $master, $slaves, $user, $pass, @conf, $line);
        if (! open(CONF, "$conffile")) {
               head("monitoring error");
               msg("Erreur à l'ouverture de $conffile : $!");
               red;
               sendreport;
               exit 1;
        }
        @conf = <CONF>;
        close(CONF);
        foreach $line (@conf) {
               if (substr($line, 0, 1) eq "#") { next }
               elsif (substr($line, 0, 1) eq "\n") { next }
               else {
                       ($node, $master, $slaves, $user, $pass) = split(/\s*;\s*/, $line, 5);
                       if ($pass) {
                               chomp $pass;
                               $auth{$node}{master} = $master;
                               foreach my $slave (split(",", $slaves)) {
                                      $auth{$node}{slaves}{$slave}{pos} = undef;
                                      $auth{$node}{slaves}{$slave}{running} = "not tested";
                               }
                               $auth{$node}{user}   = $user;
                               $auth{$node}{pass}   = $pass;
                       } else {
                               msg("&red invalid config : $line");
                               red;
                       }
               }
        }
        #print Dumper \%auth;
}


# Retourne les infos relatives au sql maitre
# <- (Position);
sub getSqlMasterStatus
{
        my ($host,$user,$pass,$base) = @_;
        my $port;
        ($host, $port) = split(/:/, $host, 2);
        if(not defined $port) {
               $port = 3306;
        }
        my $dbLink = DBI->connect("DBI:mysql:$base:$host:$port:mysql_connect_timeout=10","$user","$pass");
        if (! $dbLink) {
               $ERR = $DBI::errstr;
               red;
               return (undef);
        }
        my $query = $dbLink->prepare("SHOW MASTER STATUS");
        if (! $query->execute()) {
               $ERR = $DBI::errstr;
               red;
               return (undef);
        }
        my @results = $query->fetchrow_array;
        return "$results[0]:$results[1]";
}


# Retourne les infos relatives au sql slave

# <- (Exec_Master_Log_Pos, Slave_IO_Running&&Slave_SQL_Running)
sub getSqlSlaveStatus
{
        my ($host,$user,$pass,$base) = @_;
        my ($port, $slaverunning);
        ($host, $port) = split(/:/, $host, 2);
        if(not defined $port) {
               $port = 3306;
        }
        my $dbLink = DBI->connect("DBI:mysql:$base:$host:$port:mysql_connect_timeout=10","$user","$pass");
        if (!$dbLink) {
               red;
               $ERR = $DBI::errstr;
               return (undef);
        }
        my $query = $dbLink->prepare("SHOW SLAVE STATUS");
        $query->execute();
        if (! $query->execute()) {
               $ERR = $DBI::errstr;
               red;
               return (undef);
        }
        my @results = $query->fetchrow_array;
        ## sloppy but works :-/
        ## mysql 3.23
        if ((scalar @results) == 12) {
               return ("$results[4]:$results[5]",$results[6], $results[10]);
        }
        ## mysql 4.0
        elsif ((scalar @results) == 18) {
               if($results[9] eq "Yes" and $results[10] eq "Yes") {
                       $slaverunning = "Yes"
               }
               else {
                       $slaverunning = "No";
               }
               return ("$results[8]:$results[16]", $slaverunning, $results[14]);

        }
        ## mysql 4.1
        elsif ((scalar @results) == 33) {
               if($results[10] eq "Yes" and $results[11] eq "Yes") {
                       $slaverunning = "Yes"
               }
               else {
                       $slaverunning = "No"
               }
               return ("$results[9]:$results[21]", $slaverunning, $results[19]);
        }
        ## mysql x.q ?
        else {
               red;
               msg("Unsupported mysql version");
               return (undef, "unknown");
        }
}


###################
###################

####
# send the report
####

sub sendreport
{
        $MACHINE =~ s/\./,/g;
        my $date = localtime;
        my $cmd = "$BB $BBDISP \"status $MACHINE.$TESTNAME $COLOR $date $HEAD\n$DATA\n$MSG\"";
        if($DEBUG == 1) {
               print "$cmd\n";
        }
        else {
               system($cmd);
        }
}

sub resetreport
{
        $MSG = $DATA = $HEAD = '';
        $COLOR = 'clear';
}

# sets the global color of the test
# prevents downgrading severity
# clear == green < yellow < red
sub setcolor
{
        my $newcolor = shift;
        if ($newcolor eq "red") {
               $COLOR = "red";
        } elsif ($COLOR eq "green" or $COLOR eq "clear") {
               $COLOR = "$newcolor";
        }

        return $COLOR;
}
sub clear  { setcolor 'clear'  }
sub green  { setcolor 'green'  }
sub yellow { setcolor 'yellow' }
sub red    { setcolor 'red'    }


sub data
{
        my ($n, $v) = @_;
        $DATA .= "$n: $v\n";
}

sub head
{
        $HEAD = "@_";
}

sub msg
{
        $MSG .= join("\n", @_) . "\n";
}

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.xymon.com/pipermail/xymon/attachments/20100517/76cae0f1/attachment.html>


More information about the Xymon mailing list