package Net::ZKMon;
#
use IO::Socket;
use Carp;
use vars qw($VERSION $DEBUG);
use strict;
use Data::Dumper;
require AutoLoader;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK
$DEBUG $HOSTNAME);
use constant CLIENTPORT => 2181;
use constant BUFFER_LENGTH => 4096;
use constant DEFAULT_SOCKET_TIMEOUT => 60;
use constant DEFAULT_ZOO_CMD => 'conf';
# Note: conf command is available since ZooKeeper version 3.3.0
@ISA = qw(AutoLoader);
$VERSION = '0.02a';
sub new {
my $class = shift;
my %args = @_;
my $self = bless {
hostname => $args{hostname},
port => $args{ClientPort} || CLIENTPORT,
}, $class;
$self->debug($args{debug});
return $self;
}
sub debug {
my $class = shift;
$DEBUG = shift if @_;
$DEBUG;
}
#
# run 4 letter commands for zookeeper
#
sub _poll_zhost {
my $self = shift;
my $cmd = shift || DEFAULT_ZOO_CMD;
$self->_connect;
if ($self->{socket}) {
my $return_content;
$self->{socket}->send($cmd);
$self->{socket}->recv($return_content, BUFFER_LENGTH );
$self->{socket}->close;
return $return_content;
} else {
croak "There is no connection to host $self->{hostname} : $@ ";
}
}
sub _connect {
my $self = shift;
my $socket = ();
if ($self->{hostname}) {
$socket = IO::Socket::INET->new(
PeerAddr => $self->{hostname},
PeerPort => $self->{port},
Proto => 'tcp',
Timeout => DEFAULT_SOCKET_TIMEOUT,
Type => SOCK_STREAM,
) or
croak "Could not connect to $self->{hostname}:$self->{port}/tcp : $@";
} else {
croak "Please specify a hostname for connecting : $@ ";
}
$self->{socket} = $socket;
}
sub _structurify {
my $arr_ref = shift;
my $split_char = shift;
my $hash_result;
my @lines = split /\n/, $arr_ref;
foreach (@lines) {
chomp;
if (my ($attr, $value) = (split/$split_char/, $_)) {
$hash_result->{trim($attr)} = trim($value);
if ($attr =~ /Zookeeper version/) {
$hash_result->{'version_string'} = trim($value);
($hash_result->{'version'} = trim($value))
=~ s/(\d+\.\d+\.\d+)-.*/$1/;
}
if ($attr =~ /Latency\smin\/avg\/max/) {
($hash_result->{min_latency},
$hash_result->{avg_latency},
$hash_result->{max_latency}) = (split/\//, trim($value));
}
}
}
return $hash_result;
}
sub trim {
my $to_return = shift;
$to_return =~ s/^\s+//;
$to_return =~ s/\s+$//;
return($to_return);
}
sub mntr {
my $self = shift;
my $cmd = 'mntr';
my $hash_result =
_structurify($self->_poll_zhost($cmd), ':');
$hash_result->{'cmd'} = $cmd;
return $hash_result;
}
sub stat {
my $self = shift;
$self->{'hostname'} = shift || $self->{'hostname'};
$self->{'port'} = shift || $self->{'port'};
my $cmd = 'stat';
my $hash_result =
_structurify($self->_poll_zhost($cmd), ':');
$hash_result->{'hostname'} = $self->{'hostname'};
$hash_result->{'cmd'} = $cmd;
return $hash_result;
}
sub conf {
my $self = shift;
$self->{'hostname'} = shift || $self->{'hostname'};
$self->{'port'} = shift || $self->{'port'};
my $cmd = 'conf';
my $hash_result =
_structurify($self->_poll_zhost($cmd), '=');
$hash_result->{'hostname'} = $self->{'hostname'};
$hash_result->{'cmd'} = $cmd;
return $hash_result;
}
sub envi {
my $self = shift;
$self->{'hostname'} = shift || $self->{'hostname'};
$self->{'port'} = shift || $self->{'port'};
my $cmd = 'envi';
my $hash_result =
_structurify($self->_poll_zhost($cmd), '=');
$hash_result->{'hostname'} = $self->{'hostname'};
$hash_result->{'cmd'} = $cmd;
return $hash_result;
}
sub srvr {
my $self = shift;
$self->{'hostname'} = shift || $self->{'hostname'};
$self->{'port'} = shift || $self->{'port'};
my $cmd = 'srvr';
my $hash_result =
_structurify($self->_poll_zhost($cmd), ':');
$hash_result->{'hostname'} = $self->{'hostname'};
$hash_result->{'cmd'} = $cmd;
return $hash_result;
}
1;
__END__
=head1 NAME
Net::ZKMon
=head1 DESCRIPTION
Description :
A wrapper module around Zookeeper's 4 letter command words.
The intention is to use the abstract methods and have the resultant
data available in perl's scalar reference/hash ;
thus reducing the parsing overhead involved in the scripts.
=head1 REQUIRES
L<IO::Socket>
=head1 METHODS
=head2 new
$this->new();
=head2 conf
$this->conf();
=head2 mntr
$this->mntr();
=head2 stat
$this->stat();
=head2 envi
$this->envi();
=head2 srvr
$this->srvr();
=cut