mon-client-1.2.0/0000755003616100016640000000000010640450421013457 5ustar trockijtrockijmon-client-1.2.0/Makefile.PL0000644003616100016640000000044310064575514015445 0ustar trockijtrockij# # $Id: Makefile.PL,v 1.1.1.1 2004/06/18 14:25:16 trockij Exp $ # use ExtUtils::MakeMaker; WriteMakefile( 'NAME' => 'Mon', 'VERSION' => "1.0000", ); # version 1.0000 == 1.0.0 # ^^^^ # | | # | 3rd digit in 1.0.x # 2nd digit in 1.x.0 mon-client-1.2.0/COPYRIGHT0000644003616100016640000000146310064575514014771 0ustar trockijtrockij$Id: COPYRIGHT,v 1.1.1.1 2004/06/18 14:25:16 trockij Exp $ The code in this distribution is Copyright (c) 1997-2000 by Jim Trocki. The copyrights of individual contributions are held by the respective authors of those contributions and/or their successors in interest. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, USA; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. mon-client-1.2.0/MANIFEST0000644003616100016640000000017610064575514014627 0ustar trockijtrockijMon/Client.pm Mon/Config.pm Mon/Protocol.pm Mon/SNMP.pm MANIFEST CHANGES COPYING COPYRIGHT Makefile.PL README VERSION test.pl mon-client-1.2.0/README0000644003616100016640000000127410637737204014360 0ustar trockijtrockij# # $Id: README,v 1.1.1.1.4.1 2007/06/25 13:09:24 trockij Exp $ # $Name: mon-client-1-2-0-release $ # This is the Perl5 module for interfacing with the Mon system monitoring package. It is intended to be used in conjuction with the mon 1.2.x server. Currently only the client interface is implemented, but more things like special logging routines and persistent monitors are being considered. "mon" is a tool for monitoring the availability of services. More information can be found at http://www.kernel.org/software/mon/ To install: perl Makefile.PL make make test and if that goes well, make install Jim Trocki Software Engineer Linux Systems Group Unisys Malvern, PA mon-client-1.2.0/Mon/0000755003616100016640000000000010640450421014210 5ustar trockijtrockijmon-client-1.2.0/Mon/Config.pm0000644003616100016640000006776610064575514016014 0ustar trockijtrockij# # Perl module for interacting with a mon server # # $Id: Config.pm,v 1.1.1.1 2004/06/18 14:25:16 trockij Exp $ # # Copyright (C) 1998-2000 Jim Trocki # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # package Mon::Config; require Exporter; require 5.004; use strict; @ISA = qw(Exporter); @EXPORT_OK = qw($VERSION); $VERSION = "1.0000"; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = { "error" => "", "alias" => undef, "group" => {}, "watch" => {}, "cf" => {}, }; bless ($self, $class); return $self; } sub error { my $self = shift; return $self->{"error"}; } # # parse configuration file # # build the following data structures: # # %group # each element of %group is an array of hostnames # group records are terminated by a blank line in the # configuration file # %watch{"group"}->{"service"}->{"variable"} = value # %alias # sub read { my $self = shift; my (%args) = @_; $self->{"error"} = ""; my ($var, $watchgroup, $ingroup, $curgroup, $inwatch, $args, $hosts, %disabled, $h, $i, $inalias, $curalias); my ($sref, $pref); my ($service, $period); my ($authtype, @authtypes); my $line_num = 0; # # parse configuration file # if ($args{"m4"} || $args{"file"} =~ /\.m4$/) { if (!open (CFG, "m4 $args{file} |")) { $self->{"error"} = "could not open m4 pipe of $args{file}: $!"; return $self->{"error"}; } } else { if (!open (CFG, $CF)) { $self->{"error"} = "could not open $args{file}: $!" return $self->{"error"}; } } # # buffers to hold the new un-committed config # my %new_alias = (); my %new_CF = %CF; my %new_groups; my %new_watch; my %is_watch; my $servnum = 0; my $DEP_BEHAVIOR = "a"; my $incomplete_line = 0; my $linepart = ""; my $l = ""; my $acc_line = ""; for (;;) { # # read in a logical "line", which may span actual lines # do { $line_num++; last if (!defined ($linepart = )); next if $linepart =~ /^\s*#/; # # accumulate multi-line lines (ones which are \-escaped) # if ($incomplete_line) { $linepart =~ s/^\s*//; } if ($linepart =~ /^(.*)\\\s*$/) { $incomplete_line = 1; $acc_line .= $1; chomp $acc_line; next; } else { $acc_line .= $linepart; } $l = $acc_line; $acc_line = ""; chomp $l; $l =~ s/^\s*//; $l =~ s/\s*$//; $incomplete_line = 0; $linepart = ""; }; # # global variables which can be overriden by the command line # if (!$inwatch && $l =~ /^(\w+) \s* = \s* (.*) \s*$/ix) { if ($1 eq "alertdir") { $new_CF{"ALERTDIR"} = $2; } elsif ($1 eq "basedir") { $new_CF{"BASEDIR"} = $2; $new_CF{"BASEDIR"} = "$PWD/$new_CF{BASEDIR}" if ($new_CF{"BASEDIR"} !~ m{^/}); $new_CF{"BASEDIR"} =~ s{/$}{}; } elsif ($1 eq "cfbasedir") { $new_CF{"CFBASEDIR"} = $2; $new_CF{"CFBASEDIR"} = "$PWD/$new_CF{CFBASEDIR}" if ($new_CF{"CFBASEDIR"} !~ m{^/}); $new_CF{"CFBASEDIR"} =~ s{/$}{}; } elsif ($1 eq "mondir") { $new_CF{"SCRIPTDIR"} = $2; } elsif ($1 eq "logdir") { $new_CF{"LOGDIR"} = $2; } elsif ($1 eq "histlength") { $new_CF{"MAX_KEEP"} = $2; } elsif ($1 eq "serverport") { $new_CF{"SERVPORT"} = $2; } elsif ($1 eq "trapport") { $new_CF{"TRAPPORT"} = $2; } elsif ($1 eq "serverbind") { $new_CF{"SERVERBIND"} = $2; } elsif ($1 eq "trapbind") { $new_CF{"TRAPBIND"} = $2; } elsif ($1 eq "pidfile") { $new_CF{"PIDFILE"} = $2; } elsif ($1 eq "randstart") { $new_CF{"RANDSTART"} = dhmstos($2); if (!defined ($new_CF{"RANDSTART"})) { close (CFG); return "cf error: bad value '$2' for randstart option (syntax: historictime = timeval), line $line_num"; } } elsif ($1 eq "maxprocs") { $new_CF{"MAXPROCS"} = $2; } elsif ($1 eq "statedir") { $new_CF{"STATEDIR"} = $2; } elsif ($1 eq "authfile") { $new_CF{"AUTHFILE"} = $2; if (! -r $new_CF{"AUTHFILE"}) { close (CFG); return "cf error: authfile '$2' does not exist or is not readable, line $line_num"; } } elsif ($1 eq "authtype") { $new_CF{"AUTHTYPE"} = $2; @authtypes = split(' ' , $new_CF{"AUTHTYPE"}) ; foreach $authtype (@authtypes) { if ($authtype eq "pam") { eval 'use Authen::PAM qw(:constants);' ; if ($@ ne "") { close (CFG); return "cf error: could not use PAM authentication: $@"; } } } } elsif ($1 eq "pamservice") { $new_CF{"PAMSERVICE"} = $2; } elsif ($1 eq "userfile") { $new_CF{"USERFILE"} = $2; if (! -r $new_CF{"USERFILE"}) { close (CFG); return "cf error: userfile '$2' does not exist or is not readable, line $line_num"; } } elsif ($1 eq "ocfile") { $new_CF{"OCFILE"} = $2; } elsif ($1 eq "historicfile") { $new_CF{"HISTORICFILE"} = $2; } elsif ($1 eq "historictime") { $new_CF{"HISTORICTIME"} = dhmstos($2); if (!defined $new_CF{"HISTORICTIME"}) { close (CFG); return "cf error: bad value '$2' for historictime command (syntax: historictime = timeval), line $line_num"; } } elsif ($1 eq "cltimeout") { $new_CF{"CLIENT_TIMEOUT"} = dhmstos($2); if (!defined ($new_CF{"CLIENT_TIMEOUT"})) { close (CFG); return "cf error: bad value '$2' for cltimeout command (syntax: cltimeout = secs), line $line_num"; } } elsif ($1 eq "snmp") { if ($2 =~ /^1|yes|on|true$/i) { $new_CF{"SNMP"} = 1; eval "use SNMP"; if ($@ ne "") { close (CFG); return "cf error: could not use SNMP: $@"; } } else { $new_CF{"SNMP"} = 0; } } elsif ($1 eq "monerrfile") { $new_CF{"MONERRFILE"} = $2; } elsif ($1 eq "dtlogfile") { $new_CF{"DTLOGFILE"} = $2; } elsif ($1 eq "dtlogging") { $new_CF{"DTLOGGING"} = 0; if ($2 == 1 || $2 eq "yes" || $2 eq "true") { $new_CF{"DTLOGGING"} = 1; } } elsif ($1 eq "snmpport") { $new_CF{"SNMPPORT"} = $2; } elsif ($1 eq "dep_recur_limit") { $new_CF{"DEP_RECUR_LIMIT"} = $2; } elsif ($1 eq "dep_behavior") { if ($2 ne "m" && $2 ne "a") { close (CFG); return "cf error: unknown dependency behavior '$2', line $line_num"; } $DEP_BEHAVIOR = $2; } elsif ($1 eq "syslog_facility") { $new_CF{"SYSLOG_FACILITY"} = $2; } elsif ($1 eq "startupalerts_on_reset") { if ($2 =~ /^1|yes|true|on$/i) { $new_CF{"STARTUPALERTS_ON_RESET"} = 1; } else { $new_CF{"STARTUPALERTS_ON_RESET"} = 0; } } else { close (CFG); return "cf error: unknown variable '$1', line $line_num"; } next; } # # end of record # if ($l eq "") { $ingroup = 0; $inalias = 0; $inwatch = 0; $period = 0; $curgroup = ""; $curalias = ""; $watchgroup = ""; $servnum = 0; next; } # # hostgroup record # if ($l =~ /^hostgroup\s+([a-zA-Z0-9_.-]+)\s*(.*)/) { $curgroup = $1; $ingroup = 1; $inalias = 0; $inwatch = 0; $period = 0; $hosts = $2; %disabled = (); foreach $h (grep (/^\*/, @{$groups{$curgroup}})) { # We have to make $i = $h because $h is actually # a pointer to %groups and will modify it. $i = $h; $i =~ s/^\*//; $disabled{$i} = 1; } @{$new_groups{$curgroup}} = split(/\s+/, $hosts); # # keep hosts which were previously disabled # for ($i=0;$i<@{$new_groups{$curgroup}};$i++) { $new_groups{$curgroup}[$i] = "*$new_groups{$curgroup}[$i]" if ($disabled{$new_groups{$curgroup}[$i]}); } next; } if ($ingroup) { push (@{$new_groups{$curgroup}}, split(/\s+/, $l)); for ($i=0;$i<@{$new_groups{$curgroup}};$i++) { $new_groups{$curgroup}[$i] = "*$new_groups{$curgroup}[$i]" if ($disabled{$new_groups{$curgroup}[$i]}); } next; } # # alias record # if ($l =~ /^alias\s+([a-zA-Z0-9_.-]+)\s*$/) { $inalias = 1; $ingroup = 0; $inwatch = 0; $period = 0; $curalias = $1; next; } if ($inalias) { if ($l =~ /\A(.*)\Z/) { push (@{$new_alias{$curalias}}, $1); next; } } # # watch record # if ($l =~ /^watch\s+([a-zA-Z0-9_.-]+)\s*/) { $watchgroup = $1; $inwatch = 1; $inalias = 0; $ingroup = 0; $period = 0; if (!defined ($new_groups{$watchgroup})) { # # This hostgroup doesn't exist yet, we'll create it and warn # @{$new_groups{$watchgroup}} = ($watchgroup); print STDERR "Warning: watch group $watchgroup defined with no corresponding hostgroup.\n"; } if ($new_watch{$watchgroup}) { close (CFG); return "cf error: watch '$watchgroup' already defined, line $line_num"; } $curgroup = ""; $service = ""; next; } if ($inwatch) { # # env variables # if ($l =~ /^([A-Z_][A-Z0-9_]*)=(.*)/) { if ($service eq "") { close (CFG); return "cf error: environment variable defined without a service, line $line_num"; } $new_watch{$watchgroup}->{$service}->{"ENV"}->{$1} = $2; next; } # # non-env variables # else { $l =~ /^(\w+)\s*(.*)$/; $var = $1; $args = $2; } # # service entry # if ($var eq "service") { $service = $args; if ($service !~ /^[a-zA-Z0-9_.-]+$/) { close (CFG); return "cf error: invalid service tag '$args', line $line_num"; } $period = 0; $sref = \%{$new_watch{$watchgroup}->{$service}}; $sref->{"service"} = $args; $sref->{"interval"} = undef; $sref->{"randskew"} = 0; $sref->{"dep_behavior"} = $DEP_BEHAVIOR; $sref->{"exclude_period"} = ""; $sref->{"exclude_hosts"} = {}; $sref->{"_op_status"} = $STAT_UNTESTED; $sref->{"_last_op_status"} = $STAT_UNTESTED; $sref->{"_ack"} = 0; $sref->{"_ack_comment"} = ''; $sref->{"_consec_failures"} = 0; $sref->{"_failure_count"} = 0 if (!defined($sref->{"_failure_count"})); $sref->{"_start_of_monitor"} = time if (!defined($sref->{"_start_of_monitor"})); $sref->{"_alert_count"} = 0 if (!defined($sref->{"_alert_count"})); $sref->{"_last_failure"} = 0 if (!defined($sref->{"_last_failure"})); $sref->{"_last_success"} = 0 if (!defined($sref->{"_last_success"})); $sref->{"_last_trap"} = 0 if (!defined($sref->{"_last_trap"})); $sref->{"_exitval"} = "undef" if (!defined($sref->{"_exitval"})); $sref->{"_last_check"} = undef; $sref->{"_depend_status"} = undef; $sref->{"failure_interval"} = undef; $sref->{"_old_interval"} = undef; next; } if ($service eq "") { close (CFG); return "cf error: need to specify service in watch record, line $line_num"; } # # period definition # # for each service there can be one or more alert periods # this is stored as an array of hashes named # %{$watch{$watchgroup}->{$service}->{"periods"}} # each index for this hash is a unique tag for the period as # defined by the user or named after the period (such as # "wd {Mon-Fri} hr {7am-11pm}") # # the value of the hash is an array containing the list of alert commands # and arguments, so # # @alerts = @{$watch{$watchgroup}->{$service}->{"periods"}->{"TAG"}} # if ($var eq "period") { $period = 1; my $periodstr; if ($args =~ /^([a-z_]\w*) \s* : \s* (.*)$/ix) { $periodstr = $1; $args = $2; } else { $periodstr = $args; } $pref = \%{$sref->{"periods"}->{$periodstr}}; if (inPeriod (time, $args) == -1) { close (CFG); return "cf error: malformed period '$args' (the specified time period is not valid as per Time::Period::inPeriod), line $line_num"; } $pref->{"period"} = $args; $pref->{"alertevery"} = 0; $pref->{"numalerts"} = 0; $pref->{"_alert_sent"} = 0; $pref->{"no_comp_alerts"} = 0; @{$pref->{"alerts"}} = (); @{$pref->{"upalerts"}} = (); @{$pref->{"startupalerts"}} = (); next; } # # period variables # if ($period) { if ($var eq "alert") { push @{$pref->{"alerts"}}, $args; } elsif ($var eq "upalert") { $sref->{"_upalert"} = 1; push @{$pref->{"upalerts"}}, $args; } elsif ($var eq "startupalert") { push @{$pref->{"startupalerts"}}, $args; } elsif ($var eq "alertevery") { my $observe_detail = 0; if ($args =~ /(\S+) \s+ observe_detail \s*$/ix) { $observe_detail = 1; $args = $1; } # # for backawards-compatibility with <= 0.38.21 # elsif ($args =~ /(\S+) \s+ summary/ix) { $args = $1; } if (!($args = dhmstos ($args))) { close (CFG); return "cf error: invalid time interval '$args' (syntax: alertevery {positive number}{smhd}), line $line_num"; } $pref->{"alertevery"} = $args; $pref->{"_observe_detail"} = $observe_detail; next; } elsif ($var eq "alertafter") { my ($p1, $p2); # # alertafter NUM # if ($args =~ /^(\d+)$/) { $p1 = $1; $pref->{"alertafter_consec"} = $p1; } # # alertafter timeval # elsif ($args =~ /^(\d+[hms])$/) { $p1 = $1; if (!($p1 = dhmstos ($p1))) { close (CFG); return "cf error: invalid time interval '$args' (syntax: alertafter = [{positive integer}] [{positive number}{smhd}]), line $line_num"; } $pref->{"alertafterival"} = $p1; $pref->{"_1stfailtime"} = 0; } # # alertafter NUM timeval # elsif ($args =~ /(\d+)\s+(\d+[hms])$/) { ($p1, $p2) = ($1, $2); if (($p1 - 1) * $sref->{"interval"} >= dhmstos($p2)) { close (CFG); return "cf error: interval & alertafter not sensible. No alerts can be generated with those parameters, line $line_num"; } $pref->{"alertafter"} = $p1; $pref->{"alertafterival"} = dhmstos ($p2); $pref->{"_1stfailtime"} = 0; $pref->{"_failcount"} = 0; } else { close (CFG); return "cf error: invalid interval specification '$args', line $line_num"; } } elsif ($var eq "upalertafter") { if (!($args = dhmstos ($args))) { close (CFG); return "cf error: invalid upalertafter specification '$args' (syntax: upalertafter = {positive number}{smhd}), line $line_num"; } } elsif ($var eq "numalerts") { if ($args !~ /^\d+$/) { close (CFG); return "cf error: -numeric arg '$args' (syntax: numalerts = {positive integer}, line $line_num"; } $pref->{"numalerts"} = $args; next; } elsif ($var eq "no_comp_alerts") { $pref->{"no_comp_alerts"} = 1; next; } } # # non-period variables # elsif (!$period) { if ($var eq "interval") { if (!($args = dhmstos ($args))) { close (CFG); return "cf error: invalid time interval '$args' (syntax: interval = {positive number}{smhd}), line $line_num"; } } elsif ($var eq "failure_interval") { if (!($args = dhmstos ($args))) { close (CFG); return "cf error: invalid interval '$args' (syntax: failure_interval = {positive number}{smhd}), line $line_num"; } } elsif ($var eq "monitor") { # valid } elsif ($var eq "allow_empty_group") { # valid } elsif ($var eq "description") { # valid } elsif ($var eq "traptimeout") { if (!($args = dhmstos ($args))) { close (CFG); return "cf error: invalid traptimeout interval '$args' (syntax: traptimeout = {positive number}{smhd}), line $line_num"; } $sref->{"_trap_timer"} = $args; } elsif ($var eq "trapduration") { if (!($args = dhmstos ($args))) { close (CFG); return "cf error: invalid trapduration interval '$args' (syntax: trapduration = {positive number}{smhd}), line $line_num"; } } elsif ($var eq "randskew") { if (!($args = dhmstos ($args))) { close (CFG); return "cf error: invalid randskew time interval '$args' (syntax: randskew = {positive number}{smhd}), line $line_num"; } } elsif ($var eq "dep_behavior") { if ($args ne "m" && $args ne "a") { close (CFG); return "cf error: unknown dependency behavior '$args' (syntax: dep_behavior = {m|a}), line $line_num"; } } elsif ($var eq "depend") { $args =~ s/SELF:/$watchgroup:/g; } elsif ($var eq "exclude_hosts") { my $ex = {}; foreach my $h (split (/\s+/, $args)) { $ex->{$h} = 1; } $args = $ex; } elsif ($var eq "exclude_period" && inPeriod (time, $args) == -1) { close (CFG); return "cf error: malformed exclude_period '$args' (the specified time period is not valid as per Time::Period::inPeriod), line $line_num"; } else { close (CFG); return "cf error: unknown syntax [$l], line $line_num"; } $sref->{$var} = $args; } else { close (CFG); return "cf error: unknown syntax outside of period section [$l], line $line_num"; } } next; } close (CFG) || return "Could not open pipe to m4 (check that m4 is properly installed and in your PATH): $!"; # # Go through each defined hostgroup and check that there is a # watch associated with that hostgroup record. # # hostgroups without associated watches are not a violation of # mon config syntax, but it's usually not what you want. # for (keys(%new_watch)) { $is_watch{$_} = 1 }; foreach $watchgroup ( keys (%new_groups) ) { print STDERR "Warning: hostgroup $watchgroup has no watch assigned to it!\n" unless $is_watch{$watchgroup}; } ""; } =head1 NAME Mon::Client - Methods for interaction with Mon client =head1 SYNOPSIS use Mon::Client; =head1 DESCRIPTION Mon::Client is used to interact with "mon" clients. It supports a protocol-independent API for retrieving the status of the mon server, and performing certain operations, such as disableing hosts and service checks. =head1 METHODS =over 4 =item new Creates a new object. A hash can be supplied which sets the default values. An example which contains all of the variables that you can initialize: $c = new Mon::Client ( host => "monhost", port => 2583, username => "foo", password => "bar", ); =item password (pw) If I is provided, sets the password. Otherwise, returns the currently set password. =item host (host) If I is provided, sets the mon host. Otherwise, returns the currently set mon host. =item port (portnum) If I is provided, sets the mon port number. Otherwise, returns the currently set port number. =item username (user) If I is provided, sets the user login. Otherwise, returns the currently set user login. =item prot If I is provided, sets the protocol, specified by a string which is of the form "1.2.3", where "1" is the major revision, "2" is the minor revision, and "3" is the sub-minor revision. If I is not provided, the currently set protocol is returned. =item protid ([protocol]) Returns true if client and server protocol match, false otherwise. Implicitly called by B. If protocol is specified as an integer, supplies that protocol version to the server for verification. =item version Returns the protocol version of the remote server. =item error Returns the error string from set by the last method, or undef if there was no error. =item connected Returns 0 (not connected) or 1 (connected). =item connect (%args) Connects to the server. If B and B have not been set, uses the defaults. Returns I on error. If $args{"skip_protid"} is true, skip protocol identification upon connect. =item disconnect Disconnects from the server. Return I on error. =item login ( %hash ) B<%hash> is optional, but if specified, should contain two keys, B and B. Performs the "login" command to authenticate the user to the server. Uses B and B if specified, otherwise uses the username and password previously set by those methods, respectively. =item checkauth ( command ) Checks to see if the specified command, as executed by the current user, is authorized by the server, without actually executing the command. Returns 1 (command is authorized) or 0 (command is not authorized). =item disable_watch ( watch ) Disables B. =item disable_service ( watch, service ) Disables a service, as specified by B and B. =item disable_host ( host ) Disables B. =item enable_watch ( watch ) Enables B. =item enable_service ( watch, service ) Enables a service as specified by B and B. =item enable_host ( host ) Enables B. =item set ( group, service, var, val ) Sets B in B to B. Returns undef on error. =item get ( group, service, var ) Gets variable B in B and returns it, or undef on error. =item quit Logs out of the server. This method should be followed by a call to the B method. =item list_descriptions Returns a hash of service descriptions, indexed by watch and service. For example: %desc = $mon->list_descriptions; print "$desc{'watchname'}->{'servicename'}\n"; =item list_deps Lists dependency expressions and their components for all services. If there is no dependency for a particular service, then the value will be "NONE". %deps = $mon->list_deps; foreach $watch (keys %deps) { foreach $service (keys %{$deps{$watch}}) { my $sref = \%{$deps{$watch}->{$service}}; print "expr ($watch,$service) = $sref->{expression}\n"; print "components ($watch,$service) = @{$sref->{components}}\n"; } } =item list_group ( hostgroup ) Lists members of B. Returns an array of each member. =item list_watch Returns an array of all the defined watch groups and services. foreach $w ($mon->list_watch) { print "group=$w->[0] service=$w->[1]\n"; } =item list_opstatus ( [group1, service1], ... ) Returns a hash of per-service operational statuses, as indexed by watch and service. The list of anonymous arrays is optional, and if is not provided then the status of all groups and services will be queried. %s = $mon->list_opstatus; foreach $watch (keys %s) { foreach $service (keys %{$s{$watch}}) { foreach $var (keys %{$s{$watch}{$service}}) { print "$watch $service $var=$s{$watch}{$service}{$var}\n"; } } } =item list_failures Returns a hash in the same manner as B, but only the services which are in a failure state. =item list_successes Returns a hash in the same manner as B, but only the services which are in a success state. =item list_disabled Returns a hash of disabled watches, services, and hosts. %d = $mon->list_disabled; foreach $group (keys %{$d{"hosts"}}) { foreach $host (keys %{$d{"hosts"}{$group}}) { print "host $group/$host disabled\n"; } } foreach $watch (keys %{$d{"services"}}) { foreach $service (keys %{$d{"services"}{$watch}}) { print "service $watch/$service disabled\n"; } } for (keys %{$d{"watches"}}) { print "watch $_ disabled\n"; } =item list_alerthist Returns an array of hash references containing the alert history. @a = $mon->list_alerthist; for (@a) { print join (" ", $_->{"type"}, $_->{"watch"}, $_->{"service"}, $_->{"time"}, $_->{"alert"}, $_->{"args"}, $_->{"summary"}, "\n", ); } =item list_dtlog Returns an array of hash references containing the downtime log. @a = $mon->list_dtlog for (@a) { print join (" ", $_->{"timeup"}, $_->{"group"}, $_->{"service"}, $_->{"failtime"}, $_->{"downtime"}, $_->{"interval"}, $_->{"summary"}, "\n", ); } =item list_failurehist Returns an array of hash references containing the failure history. @f = $mon->list_failurehist; for (@f) { print join (" ", $_->{"watch"}, $_->{"service"}, $_->{"time"}, $_->{"summary"}, "\n", ); } =item list_pids Returns an array of hash references containing the list of process IDs of currently active monitors run by the server. @p = $mon->list_pids; $server = shift @p; for (@p) { print join (" ", $_->{"watch"}, $_->{"service"}, $_->{"pid"}, "\n", ); } =item list_state Lists the state of the scheduler. Returns a two-element array. The first element of the array is 0 if the scheduler is stopped, and 1 if the scheduler is currently running. The second element of the array returned is the string "scheduler running" if the scheduler is currently running, and if the scheduler is stopped, the second element is the time(2) that the scheduler was stopped. @s = $mon->list_state; if ($s[0] == 0) { print "scheduler stopped since " . localtime ($s[1]) . "\n"; } =item start Starts the scheduler. =item stop Stops the scheduler. =item reset Resets the server. =item reload ( what ) Causes the server to reload its configuration. B is an optional argument, and currently the only supported option is B, which reloads the authorization file. =item term Terminates the server. =item set_maxkeep Sets the maximum number of history entries to store in memory. =item get_maxkeep Returns the maximum number of history entries to store in memory. =item test ( test, group, service [, exitval, period]) Schedules a service test to run immediately, or tests an alert for a given period. B must be B, B, B, or B. To test alerts, the B and B must be supplied. Periods are identified by their label in the mon config file. If there are no period tags, then the actual period string must be used, exactly as it is listed in the config file. =item test_config Tests the syntax of the configuration file. Returns a two-element array. The first element of the array is 0 if the syntax of the config file is invalid, and 1 if the syntax of the config file is OK. The second element of the array returned is the failure message, if the config file has invalid syntax, and the result code if the config file syntax is OK. This function returns undef if it cannot get a connection or a response from the mon server. Config file checking stops as soon as an error is found, so you will need to run this command more than once if you have multiple errors in your config file in order to find them all. @s = $mon->test_config; if ($s[0] == 0) { print "error in config file:\n" . $s[1] . "\n"; } =item ack ( group, service, text ) When B is in a failure state, acknowledges this with B, and disables all further alerts during this failure period. =item loadstate ( state ) Loads B. =item savestate ( state ) Saves B. =item servertime Returns the time on the server using the same output as the time(2) system call. =item send_trap ( %vars ) Sends a trap to a remote mon server. Here is an example: $mon->send_trap ( group => "remote-group", service => "remote-service", retval => 1, opstatus => "fail", summary => "hosta hostb hostc", detail => "hosta hostb and hostc are unresponsive", ); I must be a nonnegative integer. I must be one of I, I, I, I, I, I, I, I. Returns I on error. =back =cut mon-client-1.2.0/Mon/SNMP.pm0000644003616100016640000001274210064575514015344 0ustar trockijtrockij=head1 NAME Mon::SNMP - decode SNMP trap =head1 SYNOPSIS use Mon::SNMP; $trap = new Mon::SNMP; $trap->buffer($snmptrap); %traphash = $trap->decode; $error = $trap->error; =head1 DESCRIPTION Mon::SNMP provides methods to decode SNMP trap PDUs. It is based on Graham Barr's Convert::BER module, and its purpose is to provide SNMP trap handling to "mon". It is not complete, so don't bother trying to use it unless you are ready to debug and write some code. =head1 METHODS =over 4 =item B creates a new Mon::SNMP object. =item B ( buffer ) Assigns a raw SNMP trap message to the object. =item B Decodes a SNMP trap message, and returns a hash of the variable assignments for the SNMP header and trap protocol data unit of the associated message. The hash consists of the following members: version => SNMP version (1) community => community string ent_OID => enterprise OID of originating agent agentaddr => IP address of originating agent generic_trap => /COLDSTART|WARMSTART|LINKDOWN|LINKUP|AUTHFAIL|EGPNEIGHBORLOSS|ENTERPRISESPECIFIC/ specific_trap => specific trap type (integer) timeticks => timeticks (integer) varbindlist => { oid1 => value, oid2 => value, ... } =back =head1 ERRORS All methods return a hash with no elements upon errors which they detect, and the detail of the error is available from the =head1 EXAMPLES use Mon::SNMP; $trap = new Mon::SNMP; $trap->buffer($snmptrap); %traphash = $trap->decode; foreach $oid (keys $traphash{"varbindlist"}) { $val = $traphash{"varbindlist"}{$oid}; print "oid($oid) = val($val)\n"; } =head1 ENVIRONMENT None. =head1 SEE ALSO Graham Barr's Convert::BER module. =head1 NOTES =head1 CAVEATS Mon::SNMP depends upon Convert::BER to do the real work. =cut # # # $Id: SNMP.pm,v 1.1.1.1 2004/06/18 14:25:16 trockij Exp $ # # Copyright (C) 1998 Jim Trocki # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # package Mon::SNMP; require Exporter; require 5.004; use Convert::BER; use Convert::BER qw(/^(\$|BER_)/); use Socket; @ISA = qw(Exporter); @EXPORT_OK = qw(@traptypes @ASN_DEFS $VERSION); $VERSION = "1.0000"; @traptypes = ("COLDSTART", "WARMSTART", "LINKDOWN", "LINKUP", "AUTHFAIL", "EGPNEIGHBORLOSS", "ENTERPRISESPECIFIC"); @ASN_DEFS = ( [ Trap_PDU => $SEQUENCE, BER_CONTEXT | BER_CONSTRUCTOR | 0x04 ], [ IpAddress => $STRING, BER_APPLICATION | 0x00 ], [ Counter => $INTEGER, BER_APPLICATION | 0x01 ], [ Gauge => $INTEGER, BER_APPLICATION | 0x02 ], [ TimeTicks => $INTEGER, BER_APPLICATION | 0x03 ], [ Opaque => undef, BER_APPLICATION | 0x04 ], ); sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; $self->{"ERROR"} = undef; $self->{"version"} = undef; $self->{"community"} = undef; $self->{"ent_OID"} = undef; $self->{"agentaddr"} = undef; $self->{"generic_trap"} = undef; $self->{"specific_trap"} = undef; $self->{"timeticks"} = undef; %{$self->{"varbindlist"}} = (); $self->{"ber_varbindlist"} = undef; $self->{"BER"} = Convert::BER->new; $self->{"BER"}->define(@ASN_DEFS); bless ($self, $class); return $self; } sub error { my $self = shift; return $self->{"ERROR"}; } sub buffer { my $self = shift; my $buf = shift; $self->{"ERROR"} = undef; $self->{"BER"}->buffer($buf); } sub decode { my $self = shift; my ($oid, $val); $self->{"ERROR"} = undef; if (! $self->{"BER"}->decode ( SEQUENCE => [ INTEGER => \$self->{"version"}, STRING => \$self->{"community"}, Trap_PDU => [ OBJECT_ID => \$self->{"ent_OID"}, IpAddress => \$self->{"agentaddr"}, INTEGER => \$self->{"generic_trap"}, INTEGER => \$self->{"specific_trap"}, TimeTicks => \$self->{"timeticks"}, SEQUENCE => [ ANY => \$self->{"ber_varbindlist"}, ], ], ], )) { $self->{"ERROR"} = "problem decoding BER"; return (); } while ($self->{"ber_varbindlist"}->decode ( SEQUENCE => [ OBJECT_ID => \$oid, ANY => \$val, ] )) { $self->{"varbindlist"}->{$oid} = $val; } return ( version => $self->{"version"}, community => $self->{"community"}, ent_OID => $self->{"ent_OID"}, agentaddr => inet_ntoa ($self->{"agentaddr"}), generic_trap => $traptypes[$self->{"generic_trap"}], specific_trap => $self->{"specific_trap"}, timeticks => $self->{"timeticks"}, varbindlist => $self->{"varbindlist"}, ); } sub dump { my $self = shift; $self->{"BER"}->dump; } mon-client-1.2.0/Mon/Protocol.pm0000644003616100016640000001726410064575514016374 0ustar trockijtrockij=head1 NAME Mon::Protocol - Methods for parsing / dumping a protocol block =head1 SYNOPSIS use Mon::Protocol; =head1 DESCRIPTION =head1 METHODS =over 4 =item new Creates a new object. A hash can be supplied which sets the default values. An example which contains all of the variables that you can initialize: $c = new Mon::Protocol; =item dump_data Returns the current internal structure as a string dump suitable for passing to C. =item C Parses a command block (from begin_block to end_block), as generated by dump_data. =item C(I) Sets or returns the type of the current command block. See @TYPES for valid type codes. In the future, it is possible that this module will perform additional checking based on the type, for now it is left to the application to interpret this. =item C Returns an array containing all section names within the block. =item C(I) Returns a hash containing the key/value pairs of the specific section. =item C(I) Completely removes the specified section from the block. =item C(I,I<$hash_ref>) Adds the key/value pairs in the hash to the specified section. $foo->add_to_section("_hostgroup", { "ns1.baz.com" -> "ok" }); =item C(I,I<$key>) Deletes the key/value pair from the section. $foo->delete_from_section("_hostgroup", "ns1.baz.com"); =item C Should any of the functions return an error (-1), this function can be used to retrieve a more elaborate error message and to reset the internal error state. =back =cut # # Perl module for parsing / dumping a mon protocol block # # $Id: Protocol.pm,v 1.1.1.1 2004/06/18 14:25:16 trockij Exp $ # # Copyright (C) 1999 Lars Marowsky-Brée # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # package Mon::Protocol; require Exporter; require 5.004; use IO::File; use Socket; sub new; sub dump_data; sub parse_data; sub type; sub get_section; sub get_section_list; sub add_to_section; sub delete_section; sub delete_from_section; sub error; sub DESTROY; sub _esc_str; sub _un_esc_str; @ISA = qw(Exporter); @EXPORT_OK = qw($VERSION @); $VERSION = "1.0000"; @TYPES = qw(cmd_monitor cmd_alert cmd_logger res_monitor res_alert res_logger); sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; my %vars = @_; $self->{'type'} = $vars{'type'} || "UNKNOWN"; bless ($self, $class); return $self; } sub dump_data { my ($self) = shift; my ($tmp); $tmp.="begin_block=".$self->{'type'}."\n"; my ($section); foreach $section (sort keys %{$self->{'data'}}) { $tmp.="begin=".$section."\n"; my ($key,$data); while ( ($key,$data) = each %{$self->{'data'}->{$section}} ) { $tmp .= "$key=". _esc_str ($data) . "\n"; } $tmp.="end=".$section."\n"; } $tmp.="end_block=".$self->{'type'}."\n"; return $tmp; } sub parse_data { my ($self) = shift; my ($raw) = @_; my (@l) = split(/\n/o,$raw); my ($l,%tmp,$type); $l = shift @l; if ($l =~ /^begin_block=(\S+)$/oi) { $type = lc($1); } else { $self->{'error'} = "No begin_block found"; return -1; } my ($section,$in_section) = ("",0); LINE: while ($l = shift @l) { next if ($l =~ /^\s*$/o); if ($in_section == 0) { if ($l =~ /^begin=(\S+)$/oi) { $section = lc($1); $in_section = 1; } elsif ($l =~ /^end_block=(\S+)$/oi) { if (lc($1) eq $type) { $in_section = -1; last LINE; } else { $self->{'error'} = "end_block does not match begin."; return -1; } } else { $self->{'error'} = "Garbled input at global level."; return -1; } } else { if ($l =~ /^end=(\S+)$/oi) { if (lc($1) eq $section) { $in_section = 0; $section = ""; next LINE; } else { $self->{'error'} = "end section does not match begin."; return -1; } } my ($key,$value); if (($key,$value) = $l =~ /^([^=]+)=(.*)/o) { $key = lc($key); $tmp{$section}{$key} = _un_esc_str ($value); } else { $self->{'error'} = "Garbled input at section level: $l"; return -1; } } } $self->{'type'} = $type; %{$self->{'data'}} = %tmp; return 0; } sub type { my ($self) = shift; if (@_) { my ($type) = lc(shift); if (grep($_ eq $type,@TYPES)) { $self->{'type'} = $type; } else { $self->{'type'} = "UNKNOWN"; $self->{'error'} = "Unknown type supplied."; return -1; } } return $self->{'type'}; } sub get_section { my ($self) = shift; my ($section) = lc(shift); if (defined($self->{'data'}->{$section})) { return %{$self->{'data'}->{$section}}; } else { $self->{'error'} = "$section: No such section."; return -1; } } sub get_section_list { my ($self) = shift; return sort keys %{$self->{'data'}}; } sub add_to_section { my ($self) = shift; my $section = lc(shift); my ($rdata) = @_; my ($key,$value); while ( ($key,$value) = each %$rdata) { $key = lc($key); $self->{'data'}->{$section}->{$key} = $value; } return 1; } sub delete_section { my ($self) = shift; my ($section) = lc(shift); if (defined($self->{'data'}->{$section})) { delete $self->{'data'}->{$section}; return 0; } else { $self->{'error'} = "$section: No such section."; return -1; } } sub delete_from_section { my ($self) = shift; my ($section) = lc(shift); my ($key) = lc(shift); if (defined($self->{'data'}->{$section}->{$key})) { delete $self->{'data'}->{$section}->{$key}; return 0; } else { $self->{'error'} = "$section/$key: No such key in section."; return -1; } } sub error { my ($self) = shift; my $err = $self->{'error'}; $self->{'error'}= ""; return $err; } sub DESTROY { my $self = shift; } # # convert a string to a hex-escaped string, returning # the escaped string. # # $str is the string to be escaped # if $inquotes is true, backslashes are doubled, making # the escaped string suitable to be enclosed in # single quotes and later passed to split # For example, var='quoted value' # sub _esc_str { my $str = shift; my $inquotes = shift; my $escstr = ""; for (my $i = 0; $i < length ($str); $i++) { my $c = substr ($str, $i, 1); if (ord ($c) <= 32 || ord ($c) > 126 || $c eq "\"" || $c eq "\'") { $c = sprintf ("\\%02x", ord($c)); } elsif ($inquotes && $c eq "\\") { $c = "\\\\"; } $escstr .= $c; } $escstr; } # # convert a hex-escaped string into an unescaped string, # returning the unescaped string # sub _un_esc_str { my $str = shift; $str =~ s{\\([0-9a-f]{2})}{chr(hex($1))}eg; $str; } 1; mon-client-1.2.0/Mon/Client.pm0000644003616100016640000012644510477327501016012 0ustar trockijtrockij# # Perl module for interacting with a mon server # # $Id: Client.pm,v 1.3 2006/09/05 17:09:21 vitroth Exp $ # # Copyright (C) 1998-2000 Jim Trocki # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # use strict; package Mon::Client; require Exporter; require 5.004; use IO::File; use Socket; use vars qw(@ISA @EXPORT_OK); BEGIN { @ISA = qw(Exporter); @EXPORT_OK = qw(%OPSTAT $VERSION); } use vars grep { /^\W/ } @EXPORT_OK; $VERSION = "1.0000"; my ($STAT_FAIL, $STAT_OK, $STAT_COLDSTART, $STAT_WARMSTART, $STAT_LINKDOWN, $STAT_UNKNOWN, $STAT_TIMEOUT, $STAT_UNTESTED, $STAT_DEPEND, $STAT_WARN) = (0..9); my ($TRAP_COLDSTART, $TRAP_WARMSTART, $TRAP_LINKDOWN, $TRAP_LINKUP, $TRAP_AUTHFAIL, $TRAP_EGPNEIGHBORLOSS, $TRAP_ENTERPRISE, $TRAP_HEARTBEAT) = (0..7); %OPSTAT = ("fail" => $STAT_FAIL, "ok" => $STAT_OK, "coldstart" => $STAT_COLDSTART, "warmstart" => $STAT_WARMSTART, "linkdown" => $STAT_LINKDOWN, "unknown" => $STAT_UNKNOWN, "timeout" => $STAT_TIMEOUT, "untested" => $STAT_UNTESTED, "dependency" => $STAT_DEPEND); my %TRAPS = ( "coldstart" => $TRAP_COLDSTART, "warmstart" => $TRAP_WARMSTART, "linkdown" => $TRAP_LINKDOWN, "linkup" => $TRAP_LINKUP, "authfail" => $TRAP_AUTHFAIL, "egpneighborloss" => $TRAP_EGPNEIGHBORLOSS, "enterprise" => $TRAP_ENTERPRISE, "heartbeat" => $TRAP_HEARTBEAT ); sub _sock_write; sub _sock_readline; sub _do_cmd; sub _list_opstatus; sub _opstatus_to_vars; sub _start_stop; sub _un_esc_str; sub _esc_str; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; my %vars = @_; if ($ENV{"MONHOST"}) { $self->{"HOST"} = $ENV{"MONHOST"}; } else { $self->{"HOST"} = undef; } $self->{"CONNECTED"} = undef; $self->{"HANDLE"} = new IO::File; $self->{"PORT"} = getservbyname ("mon", "tcp") || 2583; $self->{"PROT"} = 0x2611; $self->{"TRAP_PRO_VERSION"} = "0.3807"; $self->{"PASSWORD"} = undef; $self->{"USERNAME"} = undef; $self->{"DESCRIPTIONS"} = undef; $self->{"GROUPS"} = undef; $self->{"ERROR"} = undef; $self->{"VERSION"} = undef; if ( (defined ($ENV{"USER"}) ) && ($ENV{"USER"} ne "") ){ $self->{"USERNAME"} = $ENV{"USER"}; } else { if ($^O ne "MSWin32") { #Win32 doesn't have getpwuid :( $self->{"USERNAME"} = eval( (getpwuid ($<))[0] ); } } $self->{"OPSTATUS"} = undef; $self->{"DISABLED"} = undef; foreach my $k (keys %vars) { if ($k eq "host" && $vars{$k} ne "") { $self->{"HOST"} = $vars{$k}; } elsif ($k eq "port" && $vars{$k} ne "") { $self->{"PORT"} = $vars{$k}; } elsif ($k eq "username") { $self->{"USERNAME"} = $vars{$k}; } elsif ($k eq "password") { $self->{"PASSWORD"} = $vars{$k}; } } bless ($self, $class); return $self; } sub password { my $self = shift; if (@_) { $self->{"PASSWORD"} = shift } return $self->{"PASSWORD"}; } sub host { my $self = shift; if (@_) { $self->{"HOST"} = shift } return $self->{"HOST"}; } sub port { my $self = shift; if (@_) { $self->{"PORT"} = shift } return $self->{"PORT"}; } sub username { my $self = shift; if (@_) { $self->{"USERNAME"} = shift } return $self->{"USERNAME"}; } sub prot { my $self = shift; undef $self->{"ERROR"}; if (@_) { if ($_[0] =~ /^\d+\.\d+\.\d+$/) { $self->{"PROT"} = shift; } else { $self->{"ERROR"} = "invalid protocol version"; return undef; } } return $self->{"PROT"}; } sub DESTROY { my $self = shift; if ($self->{"CONNECTED"}) { $self->disconnect; } } sub error { my $self = shift; return $self->{"ERROR"}; } sub connected { my $self = shift; return $self->{"CONNECTED"}; } sub connect { my $self = shift; my %args = @_; my ($iaddr, $paddr, $proto); undef $self->{"ERROR"}; if ($self->{"HOST"} eq "") { $self->{"ERROR"} = "no host defined"; return undef; } if (!defined ($iaddr = inet_aton ($self->{"HOST"}))) { $self->{"ERROR"} = "could not resolve host"; return undef; } if (!defined ($paddr = sockaddr_in ($self->{"PORT"}, $iaddr))) { $self->{"ERROR"} = "could not generate sockaddr"; return undef; } if (!defined ($proto = getprotobyname ('tcp'))) { $self->{"ERROR"} = "could not getprotobyname for tcp"; return undef; } if (!defined socket ($self->{"HANDLE"}, PF_INET, SOCK_STREAM, $proto)) { $self->{"ERROR"} = "socket failed, $!"; return undef; } if (!defined connect ($self->{"HANDLE"}, $paddr)) { $self->{"ERROR"} = "connect failed, $!"; return undef; } $self->{"CONNECTED"} = 1; if (!$args{"skip_protid"}) { if (!$self->protid) { $self->{"ERROR"} = "connect failed, protocol mismatch"; close ($self->{"HANDLE"}); return undef; } } 1; } sub protid { my $self = shift; my $p = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if (!defined $p) { $p = int ($self->{"PROT"}); } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "protid $p"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } 1; } sub disconnect { my $self = shift; undef $self->{"ERROR"}; if (!defined close ($self->{"HANDLE"})) { $self->{"ERROR"} = "could not close: $!"; return undef; } $self->{"CONNECTED"} = 0; return 1; } sub login { my $self = shift; my %l = @_; undef $self->{"ERROR"}; $self->{"USERNAME"} = $l{"username"} if (defined $l{"username"}); $self->{"PASSWORD"} = $l{"password"} if (defined $l{"password"}); if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if (!defined $self->{"USERNAME"} || $self->{"USERNAME"} eq "") { $self->{"ERROR"} = "no username"; return undef; } if (!defined $self->{"PASSWORD"} || $self->{"PASSWORD"} eq "") { $self->{"ERROR"} = "no password"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "login $self->{USERNAME} $self->{PASSWORD}"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return 1; } sub checkauth { my $self = shift; my ($cmd) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($cmd eq "") { $self->{"ERROR"} = "invalid command"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "checkauth $cmd"); if ($r =~ /^220/) { return 1; } else { $self->{"ERROR"} = $r; return 0; } } sub disable_watch { my $self = shift; my ($watch) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($watch !~ /\S+/) { $self->{"ERROR"} = "invalid watch"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "disable watch $watch"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub disable_service { my $self = shift; my ($watch, $service) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($watch !~ /\S+/) { $self->{"ERROR"} = "invalid watch"; return undef; } if ($service !~ /\S+/) { $self->{"ERROR"} = "invalid service"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "disable service $watch $service"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub disable_host { my $self = shift; my (@hosts) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "disable host @hosts"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub enable_watch { my $self = shift; my ($watch) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($watch !~ /\S+/) { $self->{"ERROR"} = "invalid watch"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "enable watch $watch"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub enable_service { my $self = shift; my ($watch, $service) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($watch !~ /\S+/) { $self->{"ERROR"} = "invalid watch"; return undef; } if ($service !~ /\S+/) { $self->{"ERROR"} = "invalid service"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "enable service $watch $service"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub enable_host { my $self = shift; my (@hosts) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "enable host @hosts"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub version { my $self = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } unless (defined($self->{"VERSION"})) { my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "version"); if (!defined $r) { $self->{"ERROR"} = "error ($l)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } ($self->{"VERSION"} = $l) =~ s/^version\s+//;; } return $self->{"VERSION"}; } sub quit { my $self = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "quit"); return $r; } sub list_descriptions { my $self = shift; my ($d, $group, $service, $desc, %desc); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, @d) = _do_cmd ($self->{"HANDLE"}, "list descriptions"); if (!defined $r) { $self->{"ERROR"} = "error (@d)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r if (!defined $r); foreach $d (@d) { ($group, $service, $desc) = split (/\s+/, $d, 3); $desc{$group}{$service} = _un_esc_str (split /\s+/, $desc, 1); } return %desc; } sub list_deps { my $self = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, @d) = _do_cmd ($self->{"HANDLE"}, "list deps"); if (!defined $r) { $self->{"ERROR"} = "error (@d)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r if (!defined $r); my %dep = (); foreach my $d (@d) { my ($what, $group, $service, $l) = split (/\s+/, $d, 4); if ($what eq "exp") { $dep{$group}->{$service}->{"expression"} = _un_esc_str (split /\s+/, $l, 1); } elsif ($what eq "cmp") { @{$dep{$group}->{$service}->{"components"}} = split (/\s+/, $l); } } return %dep; } sub list_group { my $self = shift; my ($group) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($group eq "") { $self->{"ERROR"} = "invalid group"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "list group $group"); if ($r =~ /^220/) { $l =~ s/^hostgroup\s+$group\s+//;; return split (/\s+/, $l); } else { $self->{"ERROR"} = $l; return undef; } } sub list_watch { my $self = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, @l) = _do_cmd ($self->{"HANDLE"}, "list watch"); my @groups; if ($r =~ /^220/) { foreach my $l (@l) { push @groups, [split (/\s+/, $l, 2)]; } @groups; } else { $self->{"ERROR"} = $r; return undef; } } sub list_opstatus { my $self = shift; my @g = @_; if (@g == 0) { _list_opstatus ($self, "list opstatus"); } else { my @l; foreach my $i (@g) { push @l, "$i->[0],$i->[1]"; } _list_opstatus ($self, "list opstatus " . join (" ", @l)); } } sub list_failures { my $self = shift; _list_opstatus($self, "list failures"); } sub list_successes { my $self = shift; _list_opstatus($self, "list successes"); } sub list_disabled { my $self = shift; my (%disabled, $h); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, @d) = _do_cmd ($self->{"HANDLE"}, "list disabled"); if (!defined $r) { $self->{"ERROR"} = $d[0]; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } foreach $r (@d) { if ($r =~ /^group (\S+): (.*)$/) { foreach $h (split (/\s+/, $2)) { $disabled{hosts}{$1}{$h} = 1; } } elsif ($r =~ /^watch (\S+) service (\S+)$/) { $disabled{services}{$1}{$2} = 1; } elsif ($r =~ /^watch (\S+)/) { $disabled{watches}{$1} = 1; } else { next; } } return %disabled; } sub list_alerthist { my $self = shift; my (@alerts, $h, $group, $service, $time, $alert, $args, $summary); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, @h) = _do_cmd ($self->{"HANDLE"}, "list alerthist"); if (!defined $r) { $self->{"ERROR"} = "error (@h)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } foreach $h (@h) { $h = _un_esc_str ($h); my ($type, $group, $service, $time, $alert, $args, $summary) = ($h =~ /^(\S+) \s+ (\S+) \s+ (\S+) \s+ (\d+) \s+ (\S+) \s+ \(([^)]*)\) \s+ (.*)$/x); push @alerts, { type => $type, watch => $group, group => $group, service => $service, time => $time, alert => $alert, args => $args, summary => $summary }; } return @alerts; } sub list_dtlog { my $self = shift; my (@dtlog, $h, $timeup, $group, $service, $failtime, $downtime, $interval, $summary); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, @h) = _do_cmd ($self->{"HANDLE"}, "list dtlog"); if (!defined $r) { $self->{"ERROR"} = "error (@h)"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } foreach $h (@h) { $h = _un_esc_str ($h); my ($timeup, $group, $service, $failtime, $downtime, $interval, $summary) = ($h =~ /^(\d+) \s+ (\S+) \s+ (\S+) \s+ (\d+) \s+ (\d+) \s+ (\d+) \s+ (.*)$/x); push @dtlog, { timeup => $timeup, group => $group, service => $service, failtime => $failtime, downtime => $downtime, interval => $interval, summary => $summary }; } return @dtlog; } sub list_failurehist { my $self = shift; my ($r, @f, $f, $group, $service, $time, $summary, @failures); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, @f) = _do_cmd ($self->{"HANDLE"}, "list failurehist"); if (!defined $r) { $self->{"ERROR"} = "@f"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } foreach $f (@f) { ($group, $service, $time, $summary) = split (/\s+/, $f, 4); push @failures, { watch => $group, service => $service, time => $time, summary => $summary }; } return @failures; } sub list_pids { my $self = shift; my ($r, $l, @pids, @p, $p, $pid, $group, $service, $server); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, @p) = _do_cmd ($self->{"HANDLE"}, "list pids"); if (!defined $r) { $self->{"ERROR"} = "@p"; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } foreach $p (@p) { if ($p =~ /server (\d+)/) { $server = $1; } else { ($group, $service, $pid) = split (/\s+/, $p); push @pids, { watch => $group, service => $service, pid => $pid }; } } return ($server, @pids); } sub list_state { my $self = shift; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, "list state"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } if ($l =~ /scheduler running/) { return (1, $l); } elsif ($l =~ /scheduler stopped since (\d+)/) { return (0, $1); } } sub list_views { my $self = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "list views"); if ($r =~ /^220/) { $l =~ s/^views\s+//; return split (/\s+/, $l); } else { $self->{"ERROR"} = $l; return undef; } } sub start { my $self = shift; _start_stop ($self, "start"); } sub stop { my $self = shift; _start_stop ($self, "stop"); } sub reset { my $self = shift; my @opts = @_; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if (@opts == 0) { ($r, $l) = _do_cmd ($self->{"HANDLE"}, "reset"); } else { ($r, $l) = _do_cmd ($self->{"HANDLE"}, "reset @opts"); } if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub reload { my $self = shift; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, join (" ", "reload", @_)); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub term { my $self = shift; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, "term"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub set_maxkeep { my $self = shift; my $val = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($val !~ /^\d+$/) { $self->{"ERROR"} = "invalid value for maxkeep"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "set maxkeep $val"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub get_maxkeep { my $self = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "set maxkeep"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } $l =~ /maxkeep = (\d+)/; return $1; } sub set { my $self = shift; my ($group, $service, $var, $val) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "set $group $service $var " . "'" . _esc_str ($val, 1) . "'"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub setview { my $self = shift; my ($view) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "setview $view"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub get { my $self = shift; my ($group, $service, $var) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "get $group $service $var"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } ($group, $service, $var) = split (/\s+/, $l, 3); $var =~ s/^[^=]*=//; return _un_esc_str (split /\s+/, $var, 1); } sub getview { my $self = shift; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "getview"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $l; } sub test { my $self = shift; my ($what, $group, $service, $exitval, $period) = @_; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($what !~ /^monitor|alert|startupalert|upalert$/) { $self->{"ERROR"} = "unknown test"; return undef; } if (!defined $group) { $self->{"ERROR"} = "group not specified"; return undef; } if (!defined $service) { $self->{"ERROR"} = "service not specified"; return undef; } if ($what =~ /^alert|startupalert|upalert$/ && ($exitval eq "" || $period eq "")) { $self->{"ERROR"} = "must specify exit value and time period"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, join (" ", "test", $what, $group, $service, $exitval, $period)); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub test_config { my $self = shift; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, "test config"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return (0 , $l) ; } return (1 , $r); } sub ack { my $self = shift; my ($group, $service, $text) = @_; undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } $text = _esc_str ($text, 1); my ($r, $l) = _do_cmd ($self->{"HANDLE"}, "ack $group $service '$text'"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub loadstate { my $self = shift; my (@state) = @_; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, "loadstate @state"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub savestate { my $self = shift; my (@state) = @_; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, "savestate @state"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub servertime { my $self = shift; my ($r, $l, $t); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, "servertime"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } $l =~ /^(\d+)/; return $1; } # # clear timers # sub clear { my $self = shift; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, "clear timers"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } } # sub crap_cmd { # my $self = shift; # my ($r, $l); # # undef $self->{ERROR}; # # if (!$self->{CONNECTED}) { # $self->{ERROR} = "not connected"; # return undef; # } # # ($r, $l) = _do_cmd ($self->{HANDLE}, "COMMAND"); # # if (!defined $r) { # $self->{ERROR} = $l; # return undef; # } elsif ($r !~ /^220/) { # $self->{ERROR} = $r; # return undef; # } # # } sub send_trap { my $self = shift; my %v = @_; undef $self->{"ERROR"}; if ($v{"retval"} !~ /^\d+$/) { $self->{"ERROR"} = "invalid value for retval"; return undef; } if (!defined ($v{"opstatus"} = $OPSTAT{$v{"opstatus"}})) { $self->{"ERROR"} = "Undefined opstatus type"; return undef; } foreach my $k (keys %v) { $v{$k} = _esc_str ($v{$k}, 1); } my $pkt = ""; $pkt .= "pro='" . _esc_str ($self->{"TRAP_PRO_VERSION"}, 1) . "'\n"; $pkt .= "usr='" . _esc_str ($self->{"USERNAME"}, 1) . "'\n"; $pkt .= "pas='" . _esc_str ($self->{"PASSWORD"}, 1) . "'\n" if ($self->{"USERNAME"} ne ""); $pkt .= "spc='$v{opstatus}'\n" . "seq='0'\n" . "typ='trap'\n" . "grp='$v{group}'\n" . "svc='$v{service}'\n" . "sta='$v{retval}'\n" . "spc='$v{opstatus}'\n" . "tsp='" . time . "'\n" . "sum='$v{summary}'\n" . "dtl='$v{detail}'\n"; my $proto = getprotobyname ("udp"); if ($proto eq "") { $self->{"ERROR"} = "could not get proto"; return undef; } if (!socket (TRAP, AF_INET, SOCK_DGRAM, $proto)) { $self->{"ERROR"} = "could not create UDP socket: $!"; return undef; } my $port = $self->{"PORT"}; my $paddr = sockaddr_in ($port, inet_aton ($self->{"HOST"})); if (!defined (send (TRAP, $pkt, 0, $paddr))) { $self->{"ERROR"} = "could not send trap to ".$self->{"HOST"}.": $!\n"; return undef; } close (TRAP); return 1; } sub _start_stop { my $self = shift; my $cmd = shift; my ($r, $l); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } if ($cmd ne "start" && $cmd ne "stop") { $self->{"ERROR"} = "undefined command"; return undef; } ($r, $l) = _do_cmd ($self->{"HANDLE"}, "$cmd"); if (!defined $r) { $self->{"ERROR"} = $l; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } return $r; } sub _list_opstatus { my ($self, $cmd) = @_; my (%op, $o, %opstatus); my ($group, $service, $last, $timer, $summary); undef $self->{"ERROR"}; if (!$self->{"CONNECTED"}) { $self->{"ERROR"} = "not connected"; return undef; } my ($r, @op) = _do_cmd ($self->{"HANDLE"}, "$cmd"); if (!defined $r) { $self->{"ERROR"} = $op[0]; return undef; } elsif ($r !~ /^220/) { $self->{"ERROR"} = $r; return undef; } foreach $o (@op) { %op = _opstatus_to_vars ($o); next if ($op{group} eq ""); next if ($op{service} eq ""); $group = $op{"group"}; $service = $op{"service"}; foreach my $w (keys %op) { $opstatus{$group}{$service}{$w} = $op{$w}; } } return %opstatus; } sub _opstatus_to_vars { my $o = shift; my %op = (); my $parse_err = ""; # # var=something # while ($o =~ /^\s*([^=]+)=/) { my $var = $1; my $val = ""; $o =~ s/^\s*[^=]+=//; # # ='something' # if ($o =~ /^'([^']*)'/) { $val = $1; $o =~ s/^'[^']*'//; } # # =something # elsif ($o =~ /^(\S+)/) { $val = $1; $o =~ s/^\S+//; } # # = (null value) # elsif ($o =~ /^\s/) { $val = ""; $o =~ s/^\s*//; } else { # huh? } $op{$var} = _un_esc_str ($val); } %op; } sub _sock_write { my ($sock, $buf) = @_; my ($nleft, $nwritten); $nleft = length ($buf); while ($nleft) { $nwritten = syswrite ($sock, $buf, $nleft); return undef if (!defined ($nwritten)); $nleft -= $nwritten; substr ($buf, 0, $nwritten) = ""; } } sub _do_cmd { my ($fd, $cmd) = @_; my ($l, @out); @out = (); return (undef) if (!defined _sock_write ($fd, "$cmd\n")); for (;;) { $l = _sock_readline ($fd); return (undef) if (!defined $l); chomp ($l); if ($l =~ /^(\d{3}\s)/) { last; } push (@out, $l); } ($l, @out); } sub _sock_readline { my ($sock) = @_; my $l = <$sock>; return $l; } 1; # # not yet implemented # #list aliasgroups sub _esc_str { my $str = shift; my $inquotes = shift; my $escstr = ""; for (my $i = 0; $i < length ($str); $i++) { my $c = substr ($str, $i, 1); if (ord ($c) <= 32 || ord ($c) > 126 || $c eq "\"" || $c eq "\'") { $c = sprintf ("\\%02x", ord($c)); } elsif ($inquotes && $c eq "\\") { $c = "\\\\"; } $escstr .= $c; } $escstr; } sub _un_esc_str { my $str = shift; return "" unless (defined($str)); $str =~ s{\\([0-9a-f]{2})}{chr(hex($1))}eg; $str; } sub list_aliases { my $self = shift; my ($r, @d, $d, $group, $service, @allAlias, $aliasBlock, %alias); undef $self->{ERROR}; if (!$self->{CONNECTED}) { $self->{ERROR} = "not connected"; return undef; } ($r, @d) = _do_cmd ($self->{HANDLE}, "list aliases"); if (!defined $r) { $self->{ERROR} = "error (@d)"; return undef; } elsif ($r !~ /^220/) { $self->{ERROR} = $r; return undef; } return $r if (!defined $r); # the block separator is \n\n @allAlias = split (/\n\n/ ,join ("\n", @d)); foreach $aliasBlock (@allAlias) { my(@allServices, $headerAlias, @headerAlias, $nameLine, $name, $description); # extract the service block @allServices = split ( /\nservice\s*/, $aliasBlock); # The first element is not a service block, it is the alias header # alias FOO # FOO is a good service # FOO bla bla $headerAlias = shift (@allServices); # Split the block to get the name and the description @headerAlias = split (/\n/, $headerAlias); $nameLine = shift(@headerAlias); $nameLine =~ /\Aalias\s+(\S+)/; $name = $1; $headerAlias = join("\n", @headerAlias); $alias{$name}{'declaration'} = ($headerAlias) ? $headerAlias : '?'; foreach $service (@allServices) { my($serviceName, @allWatch, $watch); @allWatch = split ("\n", $service); $serviceName = shift(@allWatch); foreach $watch (@allWatch) { my($groupWatched, $serviceWatched, @items, $url); if($watch =~ /\Awatch\s+(\S+)\s+service\s+(\S+)\s+items\s*(.*)\Z/){ $groupWatched = $1; $serviceWatched = $2; @items = split(/\s+/, $3); $alias{$name}{'service'}{$serviceName}{'watch'}{$groupWatched}{'service'}{$serviceWatched}{'items'} = [ @items ]; }elsif($watch =~ /\Aurl\s+(.*)\Z/){ $url = $1; $alias{$name}{'service'}{$serviceName}{'url'} = $url; } } } } return %alias; } =head1 NAME Mon::Client - Methods for interaction with Mon client =head1 SYNOPSIS use Mon::Client; =head1 DESCRIPTION Mon::Client is used to interact with "mon" clients. It supports a protocol-independent API for retrieving the status of the mon server, and performing certain operations, such as disableing hosts and service checks. =head1 METHODS =over 4 =item new Creates a new object. A hash can be supplied which sets the default values. An example which contains all of the variables that you can initialize: $c = new Mon::Client ( host => "monhost", port => 2583, username => "foo", password => "bar", ); =item password (pw) If I is provided, sets the password. Otherwise, returns the currently set password. =item host (host) If I is provided, sets the mon host. Otherwise, returns the currently set mon host. =item port (portnum) If I is provided, sets the mon port number. Otherwise, returns the currently set port number. =item username (user) If I is provided, sets the user login. Otherwise, returns the currently set user login. =item prot If I is provided, sets the protocol, specified by a string which is of the form "1.2.3", where "1" is the major revision, "2" is the minor revision, and "3" is the sub-minor revision. If I is not provided, the currently set protocol is returned. =item protid ([protocol]) Returns true if client and server protocol match, false otherwise. Implicitly called by B. If protocol is specified as an integer, supplies that protocol version to the server for verification. =item version Returns the protocol version of the remote server. =item error Returns the error string from set by the last method, or undef if there was no error. =item connected Returns 0 (not connected) or 1 (connected). =item connect (%args) Connects to the server. If B and B have not been set, uses the defaults. Returns I on error. If $args{"skip_protid"} is true, skip protocol identification upon connect. =item disconnect Disconnects from the server. Return I on error. =item login ( %hash ) B<%hash> is optional, but if specified, should contain two keys, B and B. Performs the "login" command to authenticate the user to the server. Uses B and B if specified, otherwise uses the username and password previously set by those methods, respectively. =item checkauth ( command ) Checks to see if the specified command, as executed by the current user, is authorized by the server, without actually executing the command. Returns 1 (command is authorized) or 0 (command is not authorized). =item disable_watch ( watch ) Disables B. =item disable_service ( watch, service ) Disables a service, as specified by B and B. =item disable_host ( host ) Disables B. =item enable_watch ( watch ) Enables B. =item enable_service ( watch, service ) Enables a service as specified by B and B. =item enable_host ( host ) Enables B. =item set ( group, service, var, val ) Sets B in B to B. Returns undef on error. =item get ( group, service, var ) Gets variable B in B and returns it, or undef on error. =item quit Logs out of the server. This method should be followed by a call to the B method. =item list_descriptions Returns a hash of service descriptions, indexed by watch and service. For example: %desc = $mon->list_descriptions; print "$desc{'watchname'}->{'servicename'}\n"; =item list_deps Lists dependency expressions and their components for all services. If there is no dependency for a particular service, then the value will be "NONE". %deps = $mon->list_deps; foreach $watch (keys %deps) { foreach $service (keys %{$deps{$watch}}) { my $sref = \%{$deps{$watch}->{$service}}; print "expr ($watch,$service) = $sref->{expression}\n"; print "components ($watch,$service) = @{$sref->{components}}\n"; } } =item list_group ( hostgroup ) Lists members of B. Returns an array of each member. =item list_watch Returns an array of all the defined watch groups and services. foreach $w ($mon->list_watch) { print "group=$w->[0] service=$w->[1]\n"; } =item list_opstatus ( [group1, service1], ... ) Returns a hash of per-service operational statuses, as indexed by watch and service. The list of anonymous arrays is optional, and if is not provided then the status of all groups and services will be queried. %s = $mon->list_opstatus; foreach $watch (keys %s) { foreach $service (keys %{$s{$watch}}) { foreach $var (keys %{$s{$watch}{$service}}) { print "$watch $service $var=$s{$watch}{$service}{$var}\n"; } } } =item list_failures Returns a hash in the same manner as B, but only the services which are in a failure state. =item list_successes Returns a hash in the same manner as B, but only the services which are in a success state. =item list_disabled Returns a hash of disabled watches, services, and hosts. %d = $mon->list_disabled; foreach $group (keys %{$d{"hosts"}}) { foreach $host (keys %{$d{"hosts"}{$group}}) { print "host $group/$host disabled\n"; } } foreach $watch (keys %{$d{"services"}}) { foreach $service (keys %{$d{"services"}{$watch}}) { print "service $watch/$service disabled\n"; } } for (keys %{$d{"watches"}}) { print "watch $_ disabled\n"; } =item list_alerthist Returns an array of hash references containing the alert history. @a = $mon->list_alerthist; for (@a) { print join (" ", $_->{"type"}, $_->{"watch"}, $_->{"service"}, $_->{"time"}, $_->{"alert"}, $_->{"args"}, $_->{"summary"}, "\n", ); } =item list_dtlog Returns an array of hash references containing the downtime log. @a = $mon->list_dtlog for (@a) { print join (" ", $_->{"timeup"}, $_->{"group"}, $_->{"service"}, $_->{"failtime"}, $_->{"downtime"}, $_->{"interval"}, $_->{"summary"}, "\n", ); } =item list_failurehist Returns an array of hash references containing the failure history. @f = $mon->list_failurehist; for (@f) { print join (" ", $_->{"watch"}, $_->{"service"}, $_->{"time"}, $_->{"summary"}, "\n", ); } =item list_pids Returns an array of hash references containing the list of process IDs of currently active monitors run by the server. @p = $mon->list_pids; $server = shift @p; for (@p) { print join (" ", $_->{"watch"}, $_->{"service"}, $_->{"pid"}, "\n", ); } =item list_state Lists the state of the scheduler. Returns a two-element array. The first element of the array is 0 if the scheduler is stopped, and 1 if the scheduler is currently running. The second element of the array returned is the string "scheduler running" if the scheduler is currently running, and if the scheduler is stopped, the second element is the time(2) that the scheduler was stopped. @s = $mon->list_state; if ($s[0] == 0) { print "scheduler stopped since " . localtime ($s[1]) . "\n"; } =item start Starts the scheduler. =item stop Stops the scheduler. =item reset Resets the server. =item reload ( what ) Causes the server to reload its configuration. B is an optional argument, and currently the only supported option is B, which reloads the authorization file. =item term Terminates the server. =item set_maxkeep Sets the maximum number of history entries to store in memory. =item get_maxkeep Returns the maximum number of history entries to store in memory. =item test ( test, group, service [, exitval, period]) Schedules a service test to run immediately, or tests an alert for a given period. B must be B, B, B, or B. To test alerts, the B and B must be supplied. Periods are identified by their label in the mon config file. If there are no period tags, then the actual period string must be used, exactly as it is listed in the config file. =item test_config Tests the syntax of the configuration file. Returns a two-element array. The first element of the array is 0 if the syntax of the config file is invalid, and 1 if the syntax of the config file is OK. The second element of the array returned is the failure message, if the config file has invalid syntax, and the result code if the config file syntax is OK. This function returns undef if it cannot get a connection or a response from the mon server. Config file checking stops as soon as an error is found, so you will need to run this command more than once if you have multiple errors in your config file in order to find them all. @s = $mon->test_config; if ($s[0] == 0) { print "error in config file:\n" . $s[1] . "\n"; } =item ack ( group, service, text ) When B is in a failure state, acknowledges this with B, and disables all further alerts during this failure period. =item loadstate ( state ) Loads B. =item savestate ( state ) Saves B. =item servertime Returns the time on the server using the same output as the time(2) system call. =item send_trap ( %vars ) Sends a trap to a remote mon server. Here is an example: $mon->send_trap ( group => "remote-group", service => "remote-service", retval => 1, opstatus => "fail", summary => "hosta hostb hostc", detail => "hosta hostb and hostc are unresponsive", ); I must be a nonnegative integer. I must be one of I, I, I, I, I, I, I, I. Returns I on error. =back =cut mon-client-1.2.0/CHANGES0000644003616100016640000000674410637737177014513 0ustar trockijtrockij$Id: CHANGES,v 1.1.1.1.4.1 2007/06/25 13:09:19 trockij Exp $ $Name: mon-client-1-2-0-release $ CHANGELOG Mon Jun 25 09:08:37 EDT 2007 ---------------------------- For use with mon-1.2.x, see: http://www.kernel.org/software/mon/ Differences between 0.9901 and 1.0000: Fri Jun 18 09:38:01 EDT 2004 -------------------------------------- -slight change in _esc_str and _un_esc_str to allow opstatus to be handled by split on whitespace instead of requiring Text::Parsewords, which has in the past shown to be buggy. Differences between Mon-0.11 and 0.9901: Fri Apr 5 12:17:49 EST 2002 -------------------------------------- -win32 fixes submitted by andrew ryan -changed versioning to correspond with mon-0.99.1 -removed "quotewords" because it was causing a segfault when processing some opstatus lines. i believe perl 5.6.1 fixed the regexp processing bug which this was tripping, but sometimes it make more sense to make a workaround in 1 tiny library then to upgrade and test perl and all associated modules on a production machine. -use strict, fixed a couple bugs that uncovered Differences between Mon-0.10 and 0.11: Sun Oct 29 12:16:43 PST 2000 -------------------------------------- -incorporated Andrew Ryan's "test config" patch Differences between Mon-0.8 and 0.9: Mon Feb 28 04:59:39 PST 2000 ------------------------------------ -removed prot_cmp functions and no more support for talking with 0.37 servers. prot_cmp was making monshow fail with "unknown protocol" error. Differences between Mon-0.7 and 0.8: Tue Feb 22 08:51:42 PST 2000 ------------------------------------ -fixed the operation of the "test" command -list_opstatus now accepts ([group, service], ...) -version is now set properly -added list_watch -added protid, and optionally verify protocol ID upon connect (can be disabled, read the man page). Differences between Mon-0.6 and 0.7: Sun Feb 6 13:07:57 PST 2000 ------------------------------------ -Fixed a problem with the "test" function. It now requires the type of test as the first argument. Bug reported by andrewr@myCFO.com and rjentsch@electronicpartner.de. -reload accepts arguments such as "reload auth" -fix "list pids" output parsing to match what mon-0.38.16 does. -list_dtlog submitted by Martha H Greenberg Differences between Mon-0.5 and 0.6: Tue Nov 16 10:51:26 PST 1999 ------------------------------------ -Added Mon::Protocol. -Some code cleanups -Added new quoting rules for mon-0.38.15 -implemented get and set -supports escaped values Differences between Mon-0.4 and 0.5: ------------------------------------ -Fixed bug in old (before 0.38) opstatus parsing for Client.pm Differences between Mon-0.3 and 0.4: ------------------------------------ -Changed argument format for "prot", and added "prot_cmp", and made appropriate documentation updates. -$self->{"VERSION"} now defaults to undef (like it should), since it is not the _requested_ protocol version, it is the version obtained by asking the server. The _requested_ protocol version is specified via $self->prot(). -_list_opstatus now uses $self->prot() to figure out how to behave when talking to the server. -Export %OPSTAT for use by clients Differences between Mon-0.1 and 0.3: ------------------------------------ -Added send_trap, submitted by Lars Marowsky-Bree . -new now lets you initialize variables. -Updated docs. mon-client-1.2.0/COPYING0000644003616100016640000004322010064575514014526 0ustar trockijtrockij$Id: COPYING,v 1.1.1.1 2004/06/18 14:25:16 trockij Exp $ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mon-client-1.2.0/VERSION0000644003616100016640000000035510064575514014545 0ustar trockijtrockij$Name: mon-client-1-2-0-release $ $Log: VERSION,v $ Revision 1.1.1.1 2004/06/18 14:25:16 trockij from monperl-1-0-pre1 Revision 1.2 2004/06/14 12:57:48 trockij updated the version and "where to get more information" in the README mon-client-1.2.0/test.pl0000755003616100016640000001347710064575514015025 0ustar trockijtrockijexit; use Mon::Client; use Data::Dumper; print STDERR "new\n"; my $n = new Mon::Client ( "host" => "mon-bd2", ); print STDERR "connect\n"; if (!defined $n->connect) { die "could not connect\n"; } print STDERR "list\n"; my %s = $n->list_opstatus; print STDERR "dumper\n"; print Dumper (\%s), "\n"; $n->disconnect; exit; exit; use Mon::Protocol; use Data::Dumper; $block= <<'EOF'; begin_block=UNKNOWN begin=host1 var1=val1 var2=val2 end=host1 begin=host2 var1=people\0acannot\0ahandle\0aprofanity\0a\02\03\zz var2=val2 var3=no\0this\0code\hasn't\0been\hacked var4=this\0is\0just\0a\0test\0case\0so\don't\0get\0your\0panties\0into\0a\0knot end=host2 end_block=UNKNOWN EOF my $p = new Mon::Protocol; $p->parse_data ($block); print Dumper ($p), "\n"; exit; use Mon::Protocol; my $p = new Mon::Protocol; $p->add_to_section ("host1", { "var1" => "val1", "var2" => "val2", }); $p->add_to_section ("host2", { "var1" => "val1\nyou\nhave\nbeen\nhacked\n", "var2" => "val2", }); $a = $p->dump_data; print "$a\n"; exit; use Mon::Client; my $c = new Mon::Client ( host => "localhost", ); die if (!defined $c); $c->{"PROT"} = 9746; $c->connect ("skip_protid" => 1); if ($c->error ne "") { die "error: " . $c->error . "\n"; } if ($c->connected) { print "CONNECTED\n"; } else { print "NOT CONNECTED\n"; print $c->error . "\n"; } #my @s = $c->list_watch; $c->disconnect; exit; use Mon::Client; my $c = new Mon::Client ( host => "localhost", ); die if (!defined $c); $c->connect; if ($c->connected) { print "CONNECTED\n"; } else { print "NOT CONNECTED\n"; print $c->error . "\n"; } my %op = $c->list_opstatus (["bd1", "ping"]); foreach my $g (keys %op) { foreach my $s (keys %{$op{$g}}) { print "[$g] [$s]\n"; foreach my $v (keys %{$op{$g}->{$s}}) { print " $v=[$op{$g}->{$s}->{$v}]\n"; } } } $c->disconnect; exit; use Mon::Client; my $c = new Mon::Client ( host => "uplift", ); die if (!defined $c); if ($c->connected) { print "CONNECTED\n"; } else { print "NOT CONNECTED\n"; } if (!defined $c->connect) { die "connect error: " . $c->error . "\n"; } if ($c->connected) { print "CONNECTED\n"; } else { print "NOT CONNECTED\n"; } print $c->version, "\n"; my $v = $c->get ("router", "ping", "_timer"); if (!defined ($v)) { print STDERR "err getting\n"; } else { print "timer=$v\n"; } my $v = $c->set ("router", "ping", "_fake_timer", "up it\n50"); if (!defined ($v)) { print STDERR "err setting\n"; } else { print "timer=$v\n"; } my $v = $c->get ("router", "ping", "_fake_timer"); if (!defined ($v)) { print STDERR "err getting\n"; } else { print "timer=$v\n"; } $c->disconnect; exit; my %op = $c->list_opstatus; foreach my $g (keys %op) { foreach my $s (keys %{$op{$g}}) { print "[$g] [$s]\n"; foreach my $v (keys %{$op{$g}->{$s}}) { print " $v=[$op{$g}->{$s}->{$v}]\n"; } } } exit; exit; use Mon::Client; use Data::Dumper; my $n = new Mon::Client ( host => "localhost" ); die if (!defined $n); $n->connect; %a = $n->list_deps; $n->disconnect; print Dumper \%a, "\n"; exit; use Mon::Client; my $n = new Mon::Client ( host => "localhost" ); die if (!defined $n); $n->connect; @l = $n->list_alerthist; $n->disconnect; for my $line (sort {$a->{"time"} <=> $b->{"time"}} (@l)) { print "$line->{group} $line->{service} $line->{time}\n"; } exit; use Mon::Client; $c = new Mon::Client ( host => "localhost", port => 2583 ); die if (!defined $c); $c->connect; die "connect: " . $c->error . "\n" if ($c->error ne ""); %o = $c->list_opstatus; die "list_opstatus: " . $c->error . "\n" if ($c->error ne ""); $c->quit; foreach $g (keys %o) { foreach $s (keys %{$o{$g}}) { foreach $v (keys %{$o{$g}->{$s}}) { print "[$g] [$s] [$v] = [$o{$g}->{$s}->{$v}]\n"; } } } __END__ # # $Id: test.pl,v 1.1.1.1 2004/06/18 14:25:16 trockij Exp $ # use Mon::Client; $a = new Mon::Client ( host => "uplift", ); if (!defined $a->connect) { die "could not connect: " . $a->error . "\n"; } else { print "connected\n"; } if ((%o = $a->list_opstatus) == 0) { die "could not get optstatus: " . $a->error . "\n"; } else { print "got opstatus\n"; } #$a->username ("mon"); #$a->password ("supermon"); #if (!defined ($a->login)) { # die "could not log in: " . $a->error . "\n"; #} else { # print "logged in\n"; #} #if (!defined $a->stop) { # die "could not stop: " . $a->error . "\n"; #} #if (!defined $a->start) { # die "could not start: " . $a->error . "\n"; #} else { # print "started scheduler\n"; #} #if (!defined (%o = $a->list_failures)) { # die "could not get failures: " . $a->error . "\n"; #} %d = $a->list_disabled(); if ($a->error) { die "could not get disabled: " . $a->error . "\n"; } #if (!defined (@group = $a->list_group ("software"))) { # die "could not list group: " . $a->error . "\n"; #} #if (!defined ($a->enable_host ("pgupta-dsl"))) { # die "could not enable host: " . $a->error . "\n"; #} #if (!defined (($server, @pids) = $a->list_pids)) { # die "could not get failures: " . $a->error . "\n"; #} if (!defined $a->disconnect) { die "could not disconnect: " . $a->error . "\n"; } else { print "disconnected\n"; } &show_disabled; &show_opstatus; exit 0; sub show_disabled { print "HOSTS\n"; foreach $g (keys %{$d{hosts}}) { foreach $h (keys %{$d{hosts}{$g}}) { print "group $g [$h]\n"; } } print "SERVICES\n"; foreach $g (keys %{$d{services}}) { foreach $s (keys %{$d{services}{$g}}) { print "[$g] [$s]\n"; } } print "WATCHES\n"; foreach $g (keys %{$d{watches}}) { print "[$g]\n"; } } sub show_opstatus { my ($g, $s, $k); print "OPSTATUS\n"; foreach $g (keys %o) { foreach $s (keys %{$o{$g}}) { foreach $k (keys %{$o{$g}{$s}}) { print "[$g] [$s] [$k] [$o{$g}{$s}{$k}]\n"; } } } }