On 05/12/11 14:57, Phil Stracchino wrote:
> This is version 2.0 of my checkhost tool.

Except that somehow I accidentally attached the wrong version.  Let's
try this again.
To make up for the error, here's a standalone lanwake tool using the
same DB backend as well.




-- 
  Phil Stracchino, CDK#2     DoD#299792458     ICBM: 43.5607, -71.355
  ala...@caerllewys.net   ala...@metrocast.net   p...@co.ordinate.org
  Renaissance Man, Unix ronin, Perl hacker, SQL wrangler, Free Stater
                 It's not the years, it's the mileage.
#!/usr/bin/perl
#
# checkhost version 2.0 by Phil Stracchino
# All rights assigned to the Bacula project
# Licensed under the GPL v2, or at your option any later version
#
# Check whether a bacula client is alive and responding on the network.
# Optionally, send a wake-on-LAN packet to the client before testing.
#
# Checkhost does not perform a Bacula connection handshake or verify
# that passwords match; it only verifies that the client is reachable
# on the network and responding, and that the Bacula client is running
# and listening on port 9102.
#
# Usage:  checkhost [-r] [-v] [-i seconds] hostname|ipaddress
# Options:
#     -r, --retry:    Try three times to connect (default: try only once)
#     -i, --interval: Specify time in seconds to wait between retries
#                         (default: 30 seconds)
#     -v, --verbose:  output verbose status messages, for interactive
#                     use (default:  operate silently)
#     -w, --wake:     send wake-on-LAN packet before trying to connect
#
# Wake-on-LAN functionality requires the following schema to be created, by
# default, with a correct authentication group set up in .my.cnf for the
# group Bacula runs as:
# CREATE DATABASE ethers;
# CREATE TABLE ethers.ethers (id int primary key auto_increment,
#                             hostname varchar(128),
#                             ethers varchar(128),
#                             index host (hostname));
# The hostname field should contain a short or fully qualified hostname,
# while the ethers field should contain a list of hardware MAC addresses
# for that host, separated by spaces.

use strict;
use Getopt::Long;
use DBI;
use Socket;
use Net::Ping;
use Net::Telnet ();


# Return values:
#       -1  Program error or no host specified
#        0  Success, FD found and responding
#        1  Client alive but FD not listening
#        2  Client not found on network

my $ret = -1;
my ($etherdb, $ethergroup) = qw(ethers ethers);
my $broadcast = '10.24.32.255';
my $my_ip = '10.24.32.14';
my ($host, %opts);

die "You must set the broadcast and my_ip addresses before running this tool" 
unless ($my_ip);

Getopt::Long::Configure ("bundling");
GetOptions(\%opts,
           'interval|i=i',
           'retry|r',
           'verbose|v',
           'wake|w');

$host = shift || die "No host specified!\n";

$ret = check_host($host) if ($host);
print "Client $host not found on network\n" if ($ret == 2);
print "Returning value $ret\n" if ($opts{verbose});

exit ($ret);


sub check_host
{
    my $host = $_[0];
    my ($hostname, $p, $retrycount);

    if ($host =~ /^\d+\.\d+\.\d+\.\d+$/)
    {
        my $ip = inet_aton($host);
        $hostname = gethostbyaddr($ip, AF_INET);
        print "Host $host has name $hostname\n" if ($opts{verbose});
    }
    else
    {
        $hostname = $host;
        printf("Client $host has address %d.%d.%d.%d\n",
               unpack('C4',
                      (my @addrs = (gethostbyname($host))[4])[0]));
    }

    if ($opts{wake})
    {
        foreach my $ether (split(/\s+/, get_ethers_by_host(shift())))
        {
            wake_host_by_hwaddr($ether);
        }
        printf("Wake-on-LAN packet sent to $host; sleeping for %s seconds\n",
               $opts{interval} || 30) if ($opts{verbose});
        sleep ($opts{interval} || 30);
    }


    $p = Net::Ping->new("icmp");
    $p->bind($my_ip);

    $retrycount = ($opts{retry} ? 3 : 1);

    while ($retrycount && ($ret != 0))
    {
        if ($p->ping($host, 2))
        {
            print "Host $host is alive\n" if ($opts{verbose});
            my $t = new Net::Telnet (Timeout => 10,
                                     Port    => 9102,
                                     Prompt  => '/bash\$ $/');
            if ($t->open($host))
            {
                print "Bacula-FD listening on port 9102\n" if ($opts{verbose});
                $ret = 0;
            }
            else
            {
                print "Bacula-FD not running on host $host\n";
               $ret = 1;
            }
            $t->close;
        }
        else
        {
            $ret = 2;
        }
        $retrycount--;
        if ($opts{retry} && ($ret != 0))
        {
            printf("\tNot found on try %d",
                   3 - $retrycount) if ($opts{verbose});
            if ($retrycount)
            {
                printf("; sleeping for %s seconds before retrying\n",
                       $opts{interval} || 30) if ($opts{verbose});
                sleep($opts{interval} || 30);
            }
            else
            {
                print "\n" if ($opts{verbose});
            }
        }
    }
    $p->close();

    return ($ret);
}



sub wake_host_by_hwaddr
{
    my ($packet, $hwaddr, $raddr, $port);

    foreach (split /:/, $_[0])
    {
        $hwaddr .= chr(hex($_));
    }
    $packet = chr(0xFF) x 6 . $hwaddr x 16;
    
    socket((SOCK, AF_INET, SOCK_DGRAM, getprotobyname('udp'))) || die "socket : 
$!";
    setsockopt(SOCK, SOL_SOCKET, SO_BROADCAST, 1) || die "setsockopt : $!";

    $port = getservbyname('discard', 'udp');
    $raddr = gethostbyname($broadcast);
    send(SOCK, $packet, 0, pack_sockaddr_in($port, $raddr)) || die "send : $!";

    close (SOCK);

    return;
}


sub get_ethers_by_host
{
    my ($dbh, $sth, $query, $ethers);

    $dbh = open_db();
    $query = sprintf('SELECT ethers FROM ethers WHERE hostname = \'%s\'',
                     $_[0]);
    $sth = $dbh->prepare($query);
    $sth->execute || die "Error:" . $dbh->errstr . "\n";
    while (my $ref = $sth->fetchrow_arrayref)
    {
        $ethers = $$ref[0];
    }
    $sth->finish();
    $dbh->disconnect();

    return ($ethers);
}


sub open_db
{
    my $home = $ENV{'HOME'};
    my ($dsn, $dbh, $user, $password);

    $dsn = "DBI:mysql:database=$etherdb;"
         . "mysql_read_default_group=$ethergroup;"
         . "mysql_read_default_file=$home/.my.cnf;"
         . "mysql_mysql_client_found_rows=TRUE;"
         . "mysql_mysql_ssl=TRUE";

    $dbh = DBI->connect($dsn, undef, undef, {RaiseError => 1, AutoCommit => 0});

    return ($dbh);
}
#!/usr/bin/perl
use strict;
use DBI;
use Socket;

foreach my $ether (split(/\s+/, get_ethers_by_host(shift())))
{
    wake_host_by_hwaddr($ether);
}

exit (0);


sub wake_host_by_hwaddr
{
    my ($packet, $hwaddr, $raddr, $port);

    foreach (split /:/, $_[0])
    {
        $hwaddr .= chr(hex($_));
    }
    $packet = chr(0xFF) x 6 . $hwaddr x 16;
    
    socket((SOCK, AF_INET, SOCK_DGRAM, getprotobyname('udp'))) || die "socket : 
$!";
    setsockopt(SOCK, SOL_SOCKET, SO_BROADCAST, 1) || die "setsockopt : $!";

    $port = getservbyname('discard', 'udp');
    $raddr = gethostbyname('255.255.255.255');
    send(SOCK, $packet, 0, pack_sockaddr_in($port, $raddr)) || die "send : $!";

    close (SOCK);

    return;
}


sub get_ethers_by_host
{
    my ($dbh, $sth, $query, $ethers);

    $dbh = open_db();
    $query = sprintf('SELECT ethers FROM ethers WHERE hostname = \'%s\'',
                     $_[0]);
    $sth = $dbh->prepare($query);
    $sth->execute || die "Error:" . $dbh->errstr . "\n";
    while (my $ref = $sth->fetchrow_arrayref)
    {
        $ethers = $$ref[0];
    }
    $sth->finish();
    $dbh->disconnect();

    return ($ethers);
}


sub open_db
{
    my $home = $ENV{'HOME'};
    my ($dsn, $dbh, $user, $password);

    $dsn = "DBI:mysql:database=ethers;"
         . "mysql_read_default_group=ethers;"
         . "mysql_read_default_file=$home/.my.cnf;"
         . "mysql_mysql_client_found_rows=TRUE;"
         . "mysql_mysql_ssl=TRUE";

    $dbh = DBI->connect($dsn, undef, undef, {RaiseError => 1, AutoCommit => 0});

    return ($dbh);
}
------------------------------------------------------------------------------
Achieve unprecedented app performance and reliability
What every C/C++ and Fortran developer should know.
Learn how Intel has extended the reach of its next-generation tools
to help boost performance applications - inlcuding clusters.
http://p.sf.net/sfu/intel-dev2devmay
_______________________________________________
Bacula-users mailing list
Bacula-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bacula-users

Reply via email to