more monitoring code to support hierarchical management

git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@493 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
linggao 2008-02-16 01:25:59 +00:00
parent d46c653a7e
commit a227c6eb35
11 changed files with 981 additions and 587 deletions

View File

@ -7,11 +7,12 @@ BEGIN
}
use lib "$::XCATROOT/lib/perl";
use xCAT::NodeRange;
use Sys::Hostname;
use Socket;
use xCAT::Utils;
use xCAT::GlobalDef;
print "xCAT_monitoring::rmcmon loaded\n";
#print "xCAT_monitoring::rmcmon loaded\n";
1;
#-------------------------------------------------------------------------------
@ -34,9 +35,9 @@ print "xCAT_monitoring::rmcmon loaded\n";
in the xCAT cluster.
Arguments:
monservers --A hash reference keyed by the monitoring server nodes
and each value is a ref to an array of [nodes, nodetype] arrays
and each value is a ref to an array of [nodes, nodetype, status] arrays
monitored by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
Returns:
(return code, message)
=cut
@ -141,9 +142,9 @@ sub supportNodeStatusMon {
Arguments:
monservers --A hash reference keyed by the monitoring server nodes
and each value is a ref to an array of [nodes, nodetype] arrays
and each value is a ref to an array of [nodes, nodetype, status] arrays
monitored by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
Returns:
(return code, message)
@ -178,9 +179,9 @@ sub stopNodeStatusMon {
This function gdds the nodes into the RMC cluster.
Arguments:
nodes --nodes to be added. It is a hash reference keyed by the monitoring server
nodes and each value is a ref to an array of [nodes, nodetype] arrays monitored
nodes and each value is a ref to an array of [nodes, nodetype, status] arrays monitored
by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
verbose -- verbose mode. 1 for yes, 0 for no.
Returns:
none
@ -193,16 +194,23 @@ sub addNodes {
}
my $VERBOSE=shift;
if ($VERBOSE) { print "rmcmon::addNodes called $noderef=$noderef\n"};
#if ($VERBOSE) { print "rmcmon::addNodes called $noderef=$noderef\n"};
my $ms_host_name=hostname();
chomp($ms_host_name);
foreach (keys(%$noderef)) {
my $server=$_;
if ($VERBOSE) { print " monitoring server: $server\n";}
#if ($VERBOSE) { print " monitoring server: $server\n";}
if ($server ne $ms_host_name) {
next; #only handle the nodes which has this node as the monitor server
}
#check if rsct is installed and running
if (! -e "/usr/bin/lsrsrc") {
print "RSCT is not is not installed.\n";
next;
print "RSCT is not installed.\n";
return 1;
}
my $result=`/usr/bin/lssrc -s ctrmc`;
if ($result !~ /active/) {
@ -210,48 +218,63 @@ sub addNodes {
$result=`startsrc -s ctrmc`;
if ($?) {
print "rmc deamon cannot be started\n";
next;
return 1;
}
}
#enable remote client connection
`/usr/bin/rmcctrl -p`;
#get ms node id, hostname, ip etc
#TODO: currently one server which is where xcatd is. later changes to use server for hierachy
my $ms_node_id=`head -n 1 /var/ct/cfg/ct_node_id`;
chomp($ms_node_id);
my $ms_host_name=`hostname`;
chomp($ms_host_name);
my ($ms_name,$ms_aliases,$ms_addrtype,$ms_length,@ms_addrs) = gethostbyname($ms_host_name);
chomp($ms_name);
my $ms_ipaddresses="{";
foreach (@ms_addrs) {
$ms_ipaddresses .= '"' .inet_ntoa($_) . '",';
}
chop($ms_ipaddresses);
$ms_ipaddresses .= "}";
#ms node id, hostname, ip defs
my $ms_node_id;
my $ms_name,$ms_aliases,$ms_addrtype,$ms_length,@ms_addrs;
my $ms_ipaddresses;
#if ($VERBOSE) {
# print " ms_host_name=$ms_host_name, ms_nam=$ms_name, ms_aliases=$ms_aliases, ms_ip_addr=$ms_ipaddresses, ms_node_id=$ms_node_id\n";
#}
my $mon_nodes=$noderef->{$_};
my $first_time=1;
foreach(@$mon_nodes) {
my $node_pair=$_;
my $node=$node_pair->[0];
my $nodetype=$node_pair->[1];
if ((!$nodetype) || ($nodetype =~ /$::NODETYPE_OSI/)) {
#RMC deals only with osi type. empty type is treated as osi type
#check if the node has already defined
$result=`lsrsrc-api -s IBM.MngNode::"Name=\\\"\"$node\\\"\"" 2>&1`;
if ($? == 0) { #resource has already defined
next;
}
#TODO: check if the node is installed and ready for configuring monitor
#TODO: check all nodes at the same time or use the 'status' value in the node
`fping -a $node 2> /dev/null`;
if ($?) {
print "Cannot add the node $node into the RMC domian. The node is inactive.\n";
next;
}
if ($first_time) {
$first_time=0;
#enable remote client connection
`/usr/bin/rmcctrl -p`;
#get ms node id, hostname, ip etc
$ms_node_id=`head -n 1 /var/ct/cfg/ct_node_id`;
chomp($ms_node_id);
($ms_name,$ms_aliases,$ms_addrtype,$ms_length,@ms_addrs) = gethostbyname($ms_host_name);
chomp($ms_name);
$ms_ipaddresses="{";
foreach (@ms_addrs) {
$ms_ipaddresses .= '"' .inet_ntoa($_) . '",';
}
chop($ms_ipaddresses);
$ms_ipaddresses .= "}";
}
#get info for the node
$mn_node_id=`psh $node "head -n 1 /var/ct/cfg/ct_node_id" 2>&1`;
$mn_node_id =~ s/.*([0-9 a-g]{16}).*/$1/s;
@ -269,18 +292,22 @@ sub addNodes {
#}
# define resource in IBM.MngNode class on server
$result=`mkrsrc-api IBM.MngNode::Name::"$node"::KeyToken::"$node"::IPAddresses::"$mn_ipaddresses"::NodeID::0x$mn_node_id`;
print "define resource in IBM.MngNode class result=$result\n";
$result=`mkrsrc-api IBM.MngNode::Name::"$node"::KeyToken::"$node"::IPAddresses::"$mn_ipaddresses"::NodeID::0x$mn_node_id 2>&1`;
if ($?) {
print "define resource in IBM.MngNode class result=$result\n";
}
#copy the configuration script and run it locally
$result=`scp $::XCATROOT/lib/perl/xCAT_monitoring/rmc/configrmcnode $node:/tmp`;
if ($resul>0) {
$result=`scp $::XCATROOT/sbin/rmcmon/configrmcnode $node:/tmp 2>&1`;
if ($?) {
print "rmcmon:addNodes: cannot copy the file configrmcnode to node $node\n";
next;
}
$result=`psh $node /tmp/configrmcnode -a $node $ms_host_name $ms_ipaddresses 0x$ms_node_id`;
print "$result\n";
$result=`psh $node /tmp/configrmcnode -a $node $ms_host_name $ms_ipaddresses 0x$ms_node_id 2>&1`;
if ($?) {
print "$result\n";
}
}
}
}
@ -294,9 +321,9 @@ sub addNodes {
This function removes the nodes from the RMC cluster.
Arguments:
nodes --nodes to be removed. It is a hash reference keyed by the monitoring server
nodes and each value is a ref to an array of [nodes, nodetype] arrays monitored
nodes and each value is a ref to an array of [nodes, nodetype, status] arrays monitored
by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
verbose -- verbose mode. 1 for yes, 0 for no.
Returns:
none
@ -309,48 +336,53 @@ sub removeNodes {
}
my $VERBOSE=shift;
#if ($VERBOSE) { print "rmcmon::removeNodes called $noderef=$noderef\n"};
#if ($VERBOSE) { print "rmcmon::removeNodes called\n"};
my $local_host_name=hostname();
chomp($local_host_name);
foreach (keys(%$noderef)) {
$server=$_;
#print " monitoring server: $server\n";
#print " monitoring server: $server local_host_name=$local_host_name\n";
#only handle the nodes which has this node as the monitor server
if ($server ne $local_host_name) {next; }
my $mon_nodes=$noderef->{$_};
foreach(@$mon_nodes) {
my $node_pair=$_;
my $node=$node_pair->[0];
my $nodetype=$node_pair->[1];
#if ($VERBOSE) { print " node=$node, nodetype=$nodetype\n"; }
if ((!$nodetype) || ($nodetype =~ /$::NODETYPE_OSI/)) {
#RMC deals only with osi type. empty type is treated as osi type
#TODO: check if the node is installed and ready for configuring monitor
`fping -a $node 2> /dev/null`;
if ($?) {
print "Cannot remove node $node from the RMC domian. The node is inactive.\n";
#remove resource in IBM.MngNode class on server
my $result=`rmrsrc-api -s IBM.MngNode::"Name=\\\"\"$node\\\"\"" 2>&1`;
if ($?) { print "remove resource in IBM.MngNode class result=$result\n"; }
if ($result =~ m/2612-023/) { #resource not found
next;
}
#remove resource in IBM.MngNode class on server
my $result=`rmrsrc-api -s IBM.MngNode::"Name=\\\"\"$node\\\"\""`;
if ($VERBOSE) { print "remove resource in IBM.MngNode class result=$result\n"; }
# TODO: check all the nodes together or use the 'status' value
#if the node is inactive, forget it
`fping -a $node 2> /dev/null`;
if ($?) {
next;
}
#copy the configuration script and run it locally
$result=`scp $::XCATROOT/lib/perl/xCAT_monitoring/rmc/configrmcnode $node:/tmp`;
if ($resul>0) {
$result=`scp $::XCATROOT/sbin/rmcmon/configrmcnode $node:/tmp 2>&1 `;
if ($?) {
print "rmcmon:removeNodes: cannot copy the file configrmcnode to node $node\n";
next;
}
$result=`psh --nonodecheck $node /tmp/configrmcnode -d $node`;
print "$result\n";
$result=`psh --nonodecheck $node /tmp/configrmcnode -d $node 2>&1`;
if ($?) {
print "$result\n";
}
}
}
}
return 0;
}

View File

@ -6,7 +6,7 @@ BEGIN
$RES::Sensor{'ErrorLogSensor'} = {
Name => q(ErrorLogSensor),
Command => "$::XCATROOT/lib/perl/xCAT_monitoring/rmc/monerrorlog",
Command => "$::XCATROOT/sbin/rmcmon/monerrorlog",
UserName => q(root),
RefreshInterval => q(60),
ControlFlags => q(4),

View File

@ -6,7 +6,7 @@ BEGIN
$RES::Sensor{'CFMRootModTime'} = {
Name => q(CFMRootModTime),
Command => "$::XCATROOT/lib/perl/xCAT_monitoring/rmc/mtime /cfmroot",
Command => "$::XCATROOT/sbin/rmcmon/mtime /cfmroot",
UserName => q(root),
RefreshInterval => q(60),
};

View File

@ -1,341 +0,0 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package NodeUtils;
1;
#-------------------------------------------------------------------------------
=head1 NodeUtils module
=head2 NodeUtils module is used to store common functions for RMC monitoring on
xCAT clusters.
=cut
#-------------------------------------------------------------------------------
sub isHMC
{
my $hmcfile = "/opt/hsc/data/hmcType.properties";
if (-e $hmcfile) { return 1; }
else { return 0; }
}
#--------------------------------------------------------------------------------
=head3 runcmd
Run the given cmd and return the output in an array (already chopped). Alternatively,
if this function is used in a scalar context, the output is joined into a single string
with the newlines separating the lines.
Arguments:
command, exitcode and reference to output
Returns:
see below
Error:
Normally, if there is an error running the cmd, it will display the error msg
and exit with the cmds exit code, unless exitcode is given one of the
following values:
0: display error msg, DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-1: DO NOT display error msg and DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-2: DO the default behavior (display error msg and exit with cmds
exit code.
number > 0: Display error msg and exit with the given code
Example:
my $outref = NodeUtils->runcmd($cmd, -2, 1);
Comments:
If refoutput is true, then the output will be returned as a reference to
an array for efficiency.
=cut
#--------------------------------------------------------------------------------
sub runcmd
{
my ($class, $cmd, $exitcode, $refoutput) = @_;
$::RUNCMD_RC = 0;
if (!$::NO_STDERR_REDIRECT) {
if (!($cmd =~ /2>&1$/)) { $cmd .= ' 2>&1'; }
}
my $outref = [];
@$outref = `$cmd`;
if ($?)
{
$::RUNCMD_RC = $? >> 8;
my $displayerror = 1;
my $rc;
if (defined($exitcode) && length($exitcode) && $exitcode != -2)
{
if ($exitcode > 0)
{
$rc = $exitcode;
} # if not zero, exit with specified code
elsif ($exitcode <= 0)
{
$rc = ''; # if zero or negative, do not exit
if ($exitcode < 0) { $displayerror = 0; }
}
}
else
{
$rc = $::RUNCMD_RC;
} # if exitcode not specified, use cmd exit code
if ($displayerror)
{
my $errmsg = '';
if (($^O =~ /^linux/i) && $::RUNCMD_RC == 139)
{
$errmsg = "Segmentation fault $errmsg";
}
else
{
# The error msgs from the -api cmds are pretty messy. Clean them up a little.
NodeUtils->filterRmcApiOutput($cmd, $outref);
$errmsg = join('', @$outref);
chomp $errmsg;
}
print "Exit code $::RUNCMD_RC from command: $cmd\nError message from cmd: $errmsg\n"
}
}
if ($refoutput)
{
chomp(@$outref);
return $outref;
}
elsif (wantarray)
{
chomp(@$outref);
return @$outref;
}
else
{
my $line = join('', @$outref);
chomp $line;
return $line;
}
}
#--------------------------------------------------------------------------------
=head3 runrmccmd
Runs an RMC commmand
Arguments:
$rmccmd, $resclass, $options, $select, $exitcode, $nodelist_ref
Returns:
the output from runcmd($cmd, -2, 1)
as a ref to the output array.
Error:
none
Example:
my $outref =NodeUtils->runrmccmd('lsrsrc-api', "-i -D ':|:'", $where);
Comments:
When $nodelist_ref is not null, break it up into smaller slices
and run RMC commands seperately for each slice.
Otherwise just run RMC commands with the arguments passed in.
=cut
#--------------------------------------------------------------------------------
sub runrmccmd
{
my ($class, $rmccmd, $options, $select, $exitcode, $nodelist_ref) = @_;
my @nodelist;
my $return_ref = [];
if (!defined($exitcode))
{
$exitcode = -2;
}
if(! grep /usr\/bin/, $rmccmd)
{
# add absolute path
$rmccmd = "/usr/bin/$rmccmd";
}
if ($nodelist_ref)
{
# check whether to break up nodelist for better scalability.
@nodelist = @$nodelist_ref;
my $divide = 500; # max number of nodes for each division
my @sublist;
my @newarray;
my ($start_index, $end_index, $nodestring);
my $count = 0;
my $times = int(scalar(@nodelist) / $divide);
while ($count <= $times)
{
$start_index = $count * $divide;
$end_index =
((scalar(@nodelist) - 1) < (($count + 1) * $divide - 1))
? (scalar(@nodelist) - 1)
: (($count + 1) * $divide - 1);
@sublist = @nodelist[$start_index .. $end_index];
@newarray = ();
foreach my $node (@sublist)
{
my @vals = split ',|\s', $node;
push @newarray, @vals;
}
$nodestring = join("','", @newarray);
# replace the pattern in select string with the broken up node string
my $select_new = $select;
$select_new =~ s/XXX/$nodestring/;
my $cmd = "$rmccmd $options $select_new";
my $outref = NodeUtils->runcmd($cmd, $exitcode, 1);
push @$return_ref, @$outref;
$count++;
}
}
else
{
my $cmd = "$rmccmd $options $select";
$return_ref = NodeUtils->runcmd($cmd, $exitcode, 1);
}
# returns a reference to the output array
return $return_ref;
}
#--------------------------------------------------------------------------------
=head3 quote
Quote a string, taking into account embedded quotes. This function is most
useful when passing string through the shell to another cmd. It handles one
level of embedded double quotes, single quotes, and dollar signs.
Arguments:
string to quote
Returns:
quoted string
Globals:
none
Error:
none
Example:
Comments:
none
=cut
#--------------------------------------------------------------------------------
sub quote
{
my ($class, $str) = @_;
# if the value has imbedded double quotes, use single quotes. If it also has
# single quotes, escape the double quotes.
if (!($str =~ /\"/)) # no embedded double quotes
{
$str =~ s/\$/\\\$/sg; # escape the dollar signs
$str =~ s/\`/\\\`/sg;
$str = qq("$str");
}
elsif (!($str =~ /\'/))
{
$str = qq('$str');
} # no embedded single quotes
else # has both embedded double and single quotes
{
# Escape the double quotes. (Escaping single quotes does not seem to work
# in the shells.)
$str =~ s/\"/\\\"/sg; #" this comment helps formating
$str =~ s/\$/\\\$/sg; # escape the dollar signs
$str =~ s/\`/\\\`/sg;
$str = qq("$str");
}
}
#--------------------------------------------------------------------------------
=head3 filterRmcApiOutput
filter RMC Api Output
Arguments:
RMC command
Output reference
Returns:
none
Globals:
none
Error:
none
Example:
NodeUtils->filterRmcApiOutput($cmd, $outref);
Comments:
The error msgs from the RPM -api cmds are pretty messy.
This routine cleans them up a little bit.
=cut
#--------------------------------------------------------------------------------
sub filterRmcApiOutput
{
my ($class, $cmd, $outref) = @_;
if ($::VERBOSE || !($cmd =~ m|^/usr/bin/\S+-api |)) {
return;
} # give as much info as possible, if verbose
# Figure out the output delimiter
my ($d) = $cmd =~ / -D\s+(\S+)/;
if (length($d)) {
$d =~ s/^(\'|\")(.*)(\"|\')$/$2/; # remove any surrounding quotes
# escape any chars perl pattern matching would intepret as special chars
$d =~ s/([\|\^\*\+\?\.])/\\$1/g;
}
else
{
$d = '::';
} # this is the default output delimiter for the -api cmds
$$outref[0] =~ s/^ERROR${d}.*${d}.*${d}.*${d}.*${d}//;
}
#--------------------------------------------------------------------------------
=head3 readFile
Read a file and return its content.
Arguments:
filename
Returns:
file contents or undef
Globals:
none
Error:
undef
Comments:
none
=cut
#--------------------------------------------------------------------------------
sub readFile
{
my ($class, $filename) = @_;
open(FILE, "<$filename") or return undef;
my @contents;
@contents = <FILE>;
close(FILE);
if (wantarray) { return @contents; }
else { return join('', @contents); }
}
#--------------------------------------------------------------------------------
=head3 touchFile
Arguments: $filename, $donotExit
Returns: non zero return code indicates error
Example: NodeUtils->touchFile("/var/opt/csm/touch");
=cut
#--------------------------------------------------------------------------------
sub touchFile
{
my ($class, $filename, $donotExit) = @_;
my $fh;
my $rc = 0;
if (!-e $filename) {
#if the file doesn't exist we need to open and close it
open($fh, ">>$filename") or $rc++;
if ($rc > 0 && !$donotExit) {
print "Touch of file $filename failed with: $!\n";
return $rc;
}
close($fh) or $rc++;
}
else {
#if the file does exist we can just utime it (see the perlfunc man page entry on utime)
my $now = time;
utime($now, $now, $filename);
}
if ($rc > 0 && !$donotExit) {
print "Touch of file $filename failed with: $!\n";
return $rc;
}
return 0;
}

View File

@ -1,19 +1,144 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl/xCAT_monitoring/rmc";
use strict;
use locale;
use Getopt::Std;
use IPC::SysV qw(IPC_STAT S_IRWXU IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR );
use IPC::Msg;
use NodeUtils;
#--------------------------------------------------------------------------------
=head3 runcmd
Run the given cmd and return the output in an array (already chopped). Alternatively,
if this function is used in a scalar context, the output is joined into a single string
with the newlines separating the lines.
Arguments:
command, exitcode and reference to output
Returns:
see below
Error:
Normally, if there is an error running the cmd, it will display the error msg
and exit with the cmds exit code, unless exitcode is given one of the
following values:
0: display error msg, DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-1: DO NOT display error msg and DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-2: DO the default behavior (display error msg and exit with cmds
exit code.
number > 0: Display error msg and exit with the given code
Example:
my $outref = runcmd($cmd, -2, 1);
Comments:
If refoutput is true, then the output will be returned as a reference to
an array for efficiency.
=cut
#--------------------------------------------------------------------------------
sub runcmd
{
my ($cmd, $exitcode, $refoutput) = @_;
$::RUNCMD_RC = 0;
if (!$::NO_STDERR_REDIRECT) {
if (!($cmd =~ /2>&1$/)) { $cmd .= ' 2>&1'; }
}
my $outref = [];
@$outref = `$cmd`;
if ($?)
{
$::RUNCMD_RC = $? >> 8;
my $displayerror = 1;
my $rc;
if (defined($exitcode) && length($exitcode) && $exitcode != -2)
{
if ($exitcode > 0)
{
$rc = $exitcode;
} # if not zero, exit with specified code
elsif ($exitcode <= 0)
{
$rc = ''; # if zero or negative, do not exit
if ($exitcode < 0) { $displayerror = 0; }
}
}
else
{
$rc = $::RUNCMD_RC;
} # if exitcode not specified, use cmd exit code
if ($displayerror)
{
my $errmsg = '';
if (($^O =~ /^linux/i) && $::RUNCMD_RC == 139)
{
$errmsg = "Segmentation fault $errmsg";
}
else
{
# The error msgs from the -api cmds are pretty messy. Clean them up a little.
filterRmcApiOutput($cmd, $outref);
$errmsg = join('', @$outref);
chomp $errmsg;
}
print "Exit code $::RUNCMD_RC from command: $cmd\nError message from cmd: $errmsg\n"
}
}
if ($refoutput)
{
chomp(@$outref);
return $outref;
}
elsif (wantarray)
{
chomp(@$outref);
return @$outref;
}
else
{
my $line = join('', @$outref);
chomp $line;
return $line;
}
}
#--------------------------------------------------------------------------------
=head3 filterRmcApiOutput
filter RMC Api Output
Arguments:
RMC command
Output reference
Returns:
none
Globals:
none
Error:
none
Example:
filterRmcApiOutput($cmd, $outref);
Comments:
The error msgs from the RPM -api cmds are pretty messy.
This routine cleans them up a little bit.
=cut
#--------------------------------------------------------------------------------
sub filterRmcApiOutput
{
my ($cmd, $outref) = @_;
if ($::VERBOSE || !($cmd =~ m|^/usr/bin/\S+-api |)) {
return;
} # give as much info as possible, if verbose
# Figure out the output delimiter
my ($d) = $cmd =~ / -D\s+(\S+)/;
if (length($d)) {
$d =~ s/^(\'|\")(.*)(\"|\')$/$2/; # remove any surrounding quotes
# escape any chars perl pattern matching would intepret as special chars
$d =~ s/([\|\^\*\+\?\.])/\\$1/g;
}
else
{
$d = '::';
} # this is the default output delimiter for the -api cmds
$$outref[0] =~ s/^ERROR${d}.*${d}.*${d}.*${d}.*${d}//;
}
my $m = ord('xcat_rmc');
my $key = IPC::SysV::ftok("/var/adm/ras/errlog", $m);
@ -25,7 +150,7 @@ my $qcurrentlen = $$stat[5];
if ($qcurrentlen >= 10000) {
if (!-d "/var/opt/xcat_rmc_err_mon/") {
my $cmd = "mkdir -p \"/var/opt/xcat_rmc_err_mon\"";
NodeUtils->runcmd($cmd, -1);
runcmd($cmd, -1);
}
open(FILE, ">>/var/opt/xcat_rmc_err_mon/errmsgqueerr.log");
my $sdate = `/bin/date`;

View File

@ -1,5 +1,6 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------------------------------
=head1 mkrmcresources
=head2 mkrmcresources is used to predefine RMC conditions, responses, associations,
@ -15,19 +16,280 @@
of packaging files, script run after install or from the command line.
=cut
#-------------------------------------------------------------------------------
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl/xCAT_monitoring/rmc";
use Getopt::Long;
use NodeUtils;
$Getopt::Long::ignorecase = 0; #Checks case in GetOptions
Getopt::Long::Configure("bundling"); #allows short command line options to be grouped (e.g. -av)
#--------------------------------------------------------------------------------
=head3 quote
Quote a string, taking into account embedded quotes. This function is most
useful when passing string through the shell to another cmd. It handles one
level of embedded double quotes, single quotes, and dollar signs.
Arguments:
string to quote
Returns:
quoted string
Globals:
none
Error:
none
Example:
Comments:
none
=cut
#--------------------------------------------------------------------------------
sub quote
{
my ($str) = @_;
# if the value has imbedded double quotes, use single quotes. If it also has
# single quotes, escape the double quotes.
if (!($str =~ /\"/)) # no embedded double quotes
{
$str =~ s/\$/\\\$/sg; # escape the dollar signs
$str =~ s/\`/\\\`/sg;
$str = qq("$str");
}
elsif (!($str =~ /\'/))
{
$str = qq('$str');
} # no embedded single quotes
else # has both embedded double and single quotes
{
# Escape the double quotes. (Escaping single quotes does not seem to work
# in the shells.)
$str =~ s/\"/\\\"/sg; #" this comment helps formating
$str =~ s/\$/\\\$/sg; # escape the dollar signs
$str =~ s/\`/\\\`/sg;
$str = qq("$str");
}
}
#--------------------------------------------------------------------------------
=head3 filterRmcApiOutput
filter RMC Api Output
Arguments:
RMC command
Output reference
Returns:
none
Globals:
none
Error:
none
Example:
filterRmcApiOutput($cmd, $outref);
Comments:
The error msgs from the RPM -api cmds are pretty messy.
This routine cleans them up a little bit.
=cut
#--------------------------------------------------------------------------------
sub filterRmcApiOutput
{
my ($cmd, $outref) = @_;
if ($::VERBOSE || !($cmd =~ m|^/usr/bin/\S+-api |)) {
return;
} # give as much info as possible, if verbose
# Figure out the output delimiter
my ($d) = $cmd =~ / -D\s+(\S+)/;
if (length($d)) {
$d =~ s/^(\'|\")(.*)(\"|\')$/$2/; # remove any surrounding quotes
# escape any chars perl pattern matching would intepret as special chars
$d =~ s/([\|\^\*\+\?\.])/\\$1/g;
}
else
{
$d = '::';
} # this is the default output delimiter for the -api cmds
$$outref[0] =~ s/^ERROR${d}.*${d}.*${d}.*${d}.*${d}//;
}
sub isHMC
{
my $hmcfile = "/opt/hsc/data/hmcType.properties";
if (-e $hmcfile) { return 1; }
else { return 0; }
}
#--------------------------------------------------------------------------------
=head3 runcmd
Run the given cmd and return the output in an array (already chopped). Alternatively,
if this function is used in a scalar context, the output is joined into a single string
with the newlines separating the lines.
Arguments:
command, exitcode and reference to output
Returns:
see below
Error:
Normally, if there is an error running the cmd, it will display the error msg
and exit with the cmds exit code, unless exitcode is given one of the
following values:
0: display error msg, DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-1: DO NOT display error msg and DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-2: DO the default behavior (display error msg and exit with cmds
exit code.
number > 0: Display error msg and exit with the given code
Example:
my $outref = runcmd($cmd, -2, 1);
Comments:
If refoutput is true, then the output will be returned as a reference to
an array for efficiency.
=cut
#--------------------------------------------------------------------------------
sub runcmd
{
my ($cmd, $exitcode, $refoutput) = @_;
$::RUNCMD_RC = 0;
if (!$::NO_STDERR_REDIRECT) {
if (!($cmd =~ /2>&1$/)) { $cmd .= ' 2>&1'; }
}
my $outref = [];
@$outref = `$cmd`;
if ($?)
{
$::RUNCMD_RC = $? >> 8;
my $displayerror = 1;
my $rc;
if (defined($exitcode) && length($exitcode) && $exitcode != -2)
{
if ($exitcode > 0)
{
$rc = $exitcode;
} # if not zero, exit with specified code
elsif ($exitcode <= 0)
{
$rc = ''; # if zero or negative, do not exit
if ($exitcode < 0) { $displayerror = 0; }
}
}
else
{
$rc = $::RUNCMD_RC;
} # if exitcode not specified, use cmd exit code
if ($displayerror)
{
my $errmsg = '';
if (($^O =~ /^linux/i) && $::RUNCMD_RC == 139)
{
$errmsg = "Segmentation fault $errmsg";
}
else
{
# The error msgs from the -api cmds are pretty messy. Clean them up a little.
filterRmcApiOutput($cmd, $outref);
$errmsg = join('', @$outref);
chomp $errmsg;
}
print "Exit code $::RUNCMD_RC from command: $cmd\nError message from cmd: $errmsg\n"
}
}
if ($refoutput)
{
chomp(@$outref);
return $outref;
}
elsif (wantarray)
{
chomp(@$outref);
return @$outref;
}
else
{
my $line = join('', @$outref);
chomp $line;
return $line;
}
}
#--------------------------------------------------------------------------------
=head3 runrmccmd
Runs an RMC commmand
Arguments:
$rmccmd, $resclass, $options, $select, $exitcode, $nodelist_ref
Returns:
the output from runcmd($cmd, -2, 1)
as a ref to the output array.
Error:
none
Example:
my $outref =runrmccmd('lsrsrc-api', "-i -D ':|:'", $where);
Comments:
When $nodelist_ref is not null, break it up into smaller slices
and run RMC commands seperately for each slice.
Otherwise just run RMC commands with the arguments passed in.
=cut
#--------------------------------------------------------------------------------
sub runrmccmd
{
my ($rmccmd, $options, $select, $exitcode, $nodelist_ref) = @_;
my @nodelist;
my $return_ref = [];
if (!defined($exitcode))
{
$exitcode = -2;
}
if(! grep /usr\/bin/, $rmccmd)
{
# add absolute path
$rmccmd = "/usr/bin/$rmccmd";
}
if ($nodelist_ref)
{
# check whether to break up nodelist for better scalability.
@nodelist = @$nodelist_ref;
my $divide = 500; # max number of nodes for each division
my @sublist;
my @newarray;
my ($start_index, $end_index, $nodestring);
my $count = 0;
my $times = int(scalar(@nodelist) / $divide);
while ($count <= $times)
{
$start_index = $count * $divide;
$end_index =
((scalar(@nodelist) - 1) < (($count + 1) * $divide - 1))
? (scalar(@nodelist) - 1)
: (($count + 1) * $divide - 1);
@sublist = @nodelist[$start_index .. $end_index];
@newarray = ();
foreach my $node (@sublist)
{
my @vals = split ',|\s', $node;
push @newarray, @vals;
}
$nodestring = join("','", @newarray);
# replace the pattern in select string with the broken up node string
my $select_new = $select;
$select_new =~ s/XXX/$nodestring/;
my $cmd = "$rmccmd $options $select_new";
my $outref = runcmd($cmd, $exitcode, 1);
push @$return_ref, @$outref;
$count++;
}
}
else
{
my $cmd = "$rmccmd $options $select";
$return_ref = runcmd($cmd, $exitcode, 1);
}
# returns a reference to the output array
return $return_ref;
}
#--------------------------------------------------------------------------------
=head3 queryResources
Queries all resources of a given class or classes. Places
@ -47,7 +309,7 @@ sub queryResources
{
#special case: run lscondresp because Associations do not have names
#cant run lsrsrc because Assoctation also does not store names of resources (just handles)
my @condresp = NodeUtils->runcmd("LANG=C /usr/bin/lscondresp");
my @condresp = runcmd("LANG=C /usr/bin/lscondresp");
my $class = $res;
$class =~ s/^IBM\.//;
splice @condresp, 0,
@ -76,7 +338,7 @@ sub queryResources
}
}
my $output = NodeUtils->runrmccmd("lsrsrc-api", "-i -m -n -D ':|:'", $where);
my $output = runrmccmd("lsrsrc-api", "-i -m -n -D ':|:'", $where);
foreach my $line (@$output)
{
my @array = split(/:\|:/, $line);
@ -260,7 +522,7 @@ sub createResources
foreach my $attr (keys %{$cre{$resource}})
{
my $value = $cre{$resource}{$attr};
$string .= "${attr}::" . NodeUtils->quote($value) . "::";
$string .= "${attr}::" . quote($value) . "::";
}
if (($sensorflg == 1) && ($::INSTALL))
{
@ -279,7 +541,7 @@ sub createResources
#my $cmd = "/usr/bin/mkrsrc-api $string";
#print "running $cmd\n";
#system($cmd);
NodeUtils->runrmccmd("mkrsrc-api", "", $string);
runrmccmd("mkrsrc-api", "", $string);
$string = "";
$counter = 0;
}
@ -292,12 +554,12 @@ sub createResources
#my $cmd = "/usr/bin/mkrsrc-api $string";
#print "running $cmd\n";
#system($cmd);
NodeUtils->runrmccmd("mkrsrc-api", "", $string);
runrmccmd("mkrsrc-api", "", $string);
}
foreach my $cmd (@assoc_cmds)
{
#need to make associations after conds and resps have been made
NodeUtils->runcmd("$cmd");
runcmd("$cmd");
}
}
@ -324,15 +586,15 @@ sub changeResources
my ($cond, $resp) = split ":_:", $resource;
if ($cre{$resource}{'ActiveFlag'} == 1)
{
NodeUtils->runcmd("/usr/bin/startcondresp $cond $resp");
runcmd("/usr/bin/startcondresp $cond $resp");
if ($cre{$resource}{'Locked'} == 1)
{
NodeUtils->runcmd( "/usr/bin/startcondresp -L $cond $resp");
runcmd( "/usr/bin/startcondresp -L $cond $resp");
}
}
else
{ #not active
NodeUtils->runcmd("/usr/bin/mkcondresp $cond $resp");
runcmd("/usr/bin/mkcondresp $cond $resp");
#no need to lock stopped associations
}
}
@ -345,7 +607,7 @@ sub changeResources
foreach my $attr (keys %{$cha{$resource}})
{
my $value = $cha{$resource}{$attr};
$string .= "${attr}::" . NodeUtils->quote($value) . "::";
$string .= "${attr}::" . quote($value) . "::";
}
}
if (@unlock)
@ -362,10 +624,10 @@ sub changeResources
# here
if ($ustring =~ m/\w+/) {
NodeUtils->runrmccmd("chrsrc-api", "", $ustring, undef, \@unlock);
runrmccmd("chrsrc-api", "", $ustring, undef, \@unlock);
}
if ($string =~ m/\w+/) {
NodeUtils->runrmccmd("chrsrc-api", "", $string, undef, \@unlock);
runrmccmd("chrsrc-api", "", $string, undef, \@unlock);
}
}
@ -383,7 +645,7 @@ sub writeAllFiles
print "classes=@classes, basedir=$basedir";
foreach my $class (@classes)
{
my $output = NodeUtils->runrmccmd("lsrsrc-api", "-i", "-s ${class}::::Name");
my $output = runrmccmd("lsrsrc-api", "-i", "-s ${class}::::Name");
foreach my $line (@$output)
{
&writeFile("${class}::$line", $basedir);
@ -418,13 +680,13 @@ sub writeFile
my $file = "$basedir/$class/$resourcefilename.pm";
my $where = qq/"Name IN ('XXX')"/;
my $string = " -s ${class}::${where}::*p0x0002";
my $output = NodeUtils->runrmccmd("lsrsrc-api", "-i -n -D ':|:'",
my $output = runrmccmd("lsrsrc-api", "-i -n -D ':|:'",
$string, undef, $resource);
$string = " -s ${class}::${where}::*p0x0008";
my $optional = NodeUtils->runrmccmd("lsrsrc-api", "-i -n -D ':|:'",
my $optional = runrmccmd("lsrsrc-api", "-i -n -D ':|:'",
$string, undef, $resource);
#my @output = NodeUtils->runcmd("/usr/bin/lsrsrc -s $where $class");
#my @output = runcmd("/usr/bin/lsrsrc -s $where $class");
#uses lsrsrc instead of lsrsrc-api because format is almost right (just needs a few mods)
my $fh;
@ -530,7 +792,7 @@ if (
}
if ($::HELP) { &usage; exit; }
if (NodeUtils->isHMC() && ($ENV{'DC_ENVIRONMENT'} ne 1))
if (isHMC() && ($ENV{'DC_ENVIRONMENT'} ne 1))
{
print "mkresources is not supported on HMC.\n";
}

View File

@ -9,11 +9,11 @@
checks for errors.
=cut
#------------------------------------------------------------------------------
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl/xCAT_monitoring/rmc";
use strict;
use locale;
@ -21,7 +21,174 @@ use locale;
use Getopt::Std;
use IPC::SysV qw(IPC_STAT S_IRWXU IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR );
use IPC::Msg;
use NodeUtils;
#--------------------------------------------------------------------------------
=head3 runcmd
Run the given cmd and return the output in an array (already chopped). Alternatively,
if this function is used in a scalar context, the output is joined into a single string
with the newlines separating the lines.
Arguments:
command, exitcode and reference to output
Returns:
see below
Error:
Normally, if there is an error running the cmd, it will display the error msg
and exit with the cmds exit code, unless exitcode is given one of the
following values:
0: display error msg, DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-1: DO NOT display error msg and DO NOT exit on error, but set
$::RUNCMD_RC to the exit code.
-2: DO the default behavior (display error msg and exit with cmds
exit code.
number > 0: Display error msg and exit with the given code
Example:
my $outref = runcmd($cmd, -2, 1);
Comments:
If refoutput is true, then the output will be returned as a reference to
an array for efficiency.
=cut
#--------------------------------------------------------------------------------
sub runcmd
{
my ($cmd, $exitcode, $refoutput) = @_;
$::RUNCMD_RC = 0;
if (!$::NO_STDERR_REDIRECT) {
if (!($cmd =~ /2>&1$/)) { $cmd .= ' 2>&1'; }
}
my $outref = [];
@$outref = `$cmd`;
if ($?)
{
$::RUNCMD_RC = $? >> 8;
my $displayerror = 1;
my $rc;
if (defined($exitcode) && length($exitcode) && $exitcode != -2)
{
if ($exitcode > 0)
{
$rc = $exitcode;
} # if not zero, exit with specified code
elsif ($exitcode <= 0)
{
$rc = ''; # if zero or negative, do not exit
if ($exitcode < 0) { $displayerror = 0; }
}
}
else
{
$rc = $::RUNCMD_RC;
} # if exitcode not specified, use cmd exit code
if ($displayerror)
{
my $errmsg = '';
if (($^O =~ /^linux/i) && $::RUNCMD_RC == 139)
{
$errmsg = "Segmentation fault $errmsg";
}
else
{
# The error msgs from the -api cmds are pretty messy. Clean them up a little.
filterRmcApiOutput($cmd, $outref);
$errmsg = join('', @$outref);
chomp $errmsg;
}
print "Exit code $::RUNCMD_RC from command: $cmd\nError message from cmd: $errmsg\n"
}
}
if ($refoutput)
{
chomp(@$outref);
return $outref;
}
elsif (wantarray)
{
chomp(@$outref);
return @$outref;
}
else
{
my $line = join('', @$outref);
chomp $line;
return $line;
}
}
#--------------------------------------------------------------------------------
=head3 filterRmcApiOutput
filter RMC Api Output
Arguments:
RMC command
Output reference
Returns:
none
Globals:
none
Error:
none
Example:
filterRmcApiOutput($cmd, $outref);
Comments:
The error msgs from the RPM -api cmds are pretty messy.
This routine cleans them up a little bit.
=cut
#--------------------------------------------------------------------------------
sub filterRmcApiOutput
{
my ($cmd, $outref) = @_;
if ($::VERBOSE || !($cmd =~ m|^/usr/bin/\S+-api |)) {
return;
} # give as much info as possible, if verbose
# Figure out the output delimiter
my ($d) = $cmd =~ / -D\s+(\S+)/;
if (length($d)) {
$d =~ s/^(\'|\")(.*)(\"|\')$/$2/; # remove any surrounding quotes
# escape any chars perl pattern matching would intepret as special chars
$d =~ s/([\|\^\*\+\?\.])/\\$1/g;
}
else
{
$d = '::';
} # this is the default output delimiter for the -api cmds
$$outref[0] =~ s/^ERROR${d}.*${d}.*${d}.*${d}.*${d}//;
}
#--------------------------------------------------------------------------------
=head3 touchFile
Arguments: $filename, $donotExit
Returns: non zero return code indicates error
Example: touchFile("/var/opt/xcat/touch");
=cut
#--------------------------------------------------------------------------------
sub touchFile
{
my ($filename, $donotExit) = @_;
my $fh;
my $rc = 0;
if (!-e $filename) {
#if the file doesn't exist we need to open and close it
open($fh, ">>$filename") or $rc++;
if ($rc > 0 && !$donotExit) {
print "Touch of file $filename failed with: $!\n";
return $rc;
}
close($fh) or $rc++;
}
else {
#if the file does exist we can just utime it (see the perlfunc man page entry on utime)
my $now = time;
utime($now, $now, $filename);
}
if ($rc > 0 && !$donotExit) {
print "Touch of file $filename failed with: $!\n";
return $rc;
}
return 0;
}
#do nothing on Linux when stopping.
if (($ENV{'SENSOR_MonitorStatus'} eq '2') && ($^O =~ /^linux/i)) {
@ -48,7 +215,7 @@ if (!-d $vardir) { mkdir($vardir); }
sub isRMrunning{
my $resMan = $_[0];
my @output = NodeUtils->runcmd("LANG=C /usr/bin/lssrc -s $resMan", -1);
my @output = runcmd("LANG=C /usr/bin/lssrc -s $resMan", -1);
if ($::RUNCMD_RC) { return 0; } # maybe we should try to catch real errors here
my ($subsys, $group, $pid, $status) = split(' ', $output[1]);
if (defined($status) && $status eq 'active') {
@ -61,16 +228,16 @@ sub isRMrunning{
if (!-e $runfile){
#first time
if ($^O =~ /^linux/i) {
NodeUtils->runcmd("grep $dirname $syslogconf", -1);
runcmd("grep $dirname $syslogconf", -1);
if ($::RUNCMD_RC == 1) { #grep did not find dirname
#update syslog.conf
if (!-d $vardir) { mkdir($vardir); }
NodeUtils->runcmd("/usr/bin/mkfifo $fifo");
NodeUtils->runcmd("echo \"$embedinfo\" >> $syslogconf");
runcmd("/usr/bin/mkfifo $fifo");
runcmd("echo \"$embedinfo\" >> $syslogconf");
my $cmd = service("syslog", "restart");
NodeUtils->runcmd($cmd);
runcmd($cmd);
}
NodeUtils->touchFile($runfile);
touchFile($runfile);
}
elsif ($^O =~ /^aix/i) {
open(ODM, ">$odmstanza") or die $!;
@ -79,11 +246,11 @@ errnotify:
en_pid = 0
en_name = "xcat_rmc_errlog_sensor"
en_persistenceflg = 1
en_method = "' . "$::XCATROOT/lib/perl/xCAT_monitoring/rmc/errmsgque" . ' sequence = $1 error_id = $2 class = $3 type = $4 alert_flags = $5 res_name = $6 res_type = $7 res_class = $8 label = $9"
en_method = "' . "$::XCATROOT/sbin/rmcmon/errmsgque" . ' sequence = $1 error_id = $2 class = $3 type = $4 alert_flags = $5 res_name = $6 res_type = $7 res_class = $8 label = $9"
';
close ODM or die $!;
NodeUtils->runcmd("/usr/bin/odmadd $odmstanza");
NodeUtils->touchFile($runfile);
runcmd("/usr/bin/odmadd $odmstanza");
touchFile($runfile);
}
else {
print "unknown platform\n";
@ -117,7 +284,7 @@ if ($^O =~ /^linux/i) {
chomp($line);
#print "String=\"$line\"\n";
NodeUtils->runcmd(
runcmd(
"echo \"/usr/bin/refsensor ErrorLogSensor String=\'$line\' 1>/dev/null 2>/dev/null\" | at now",0);
}
close PIPE;
@ -129,7 +296,7 @@ elsif ($^O =~ /^aix/i) {
# set $ENV{'SENSOR_MonitorStatus'} to 2
# should not do clean up when IBM.SensorRM is stopped
if (&isRMrunning("IBM.SensorRM")) {
NodeUtils->runcmd("/bin/odmdelete -o errnotify -q \" en_name=xcat_rmc_errlog_sens\"", -1);
runcmd("/bin/odmdelete -o errnotify -q \" en_name=xcat_rmc_errlog_sens\"", -1);
if (-e $runfile) {
unlink($runfile);
}
@ -149,7 +316,7 @@ elsif ($^O =~ /^aix/i) {
alarm 0;
};
if ($@ =~ /alarm/) { close PIPE; exit 0; }
NodeUtils->runcmd(
runcmd(
"echo \"/usr/bin/refsensor ErrorLogSensor String=\'$buf\' 1>/dev/null 2>/dev/null\" | at now", 0);
}
@ -172,10 +339,10 @@ sub verify_atd
{
my $cmd;
$cmd = service("atd", "status");
NodeUtils->runcmd($cmd, -1);
runcmd($cmd, -1);
if ($::RUNCMD_RC) {
$cmd = service("atd", "start");
NodeUtils->runcmd($cmd, -1);
runcmd($cmd, -1);
if ($::RUNCMD_RC) {
print "Warning: atd has failed to start!\n";
}
@ -209,7 +376,7 @@ sub service
my $SVCDIR = "/etc/init.d";
# On SLES, nfs server script is "nfsserver".
if (((-e "/etc/SuSE-release") || NodeUtils->isHMC()) && $service eq "nfs") {
if (((-e "/etc/SuSE-release") || isHMC()) && $service eq "nfs") {
$service = "nfsserver";
}
if (-f $SVCCLI) {
@ -221,6 +388,13 @@ sub service
return $cmd;
}
sub isHMC
{
my $hmcfile = "/opt/hsc/data/hmcType.properties";
if (-e $hmcfile) { return 1; }
else { return 0; }
}
exit 0;

View File

@ -14,6 +14,9 @@ BuildRoot: /var/tmp/%{name}-%{version}-%{release}-root
BuildArch: noarch
%endif
Requires: perl-xCAT = %{version}
Requires: xCAT-server = %{version}
Provides: xCAT-rmc = %{version}
%description

View File

@ -14,6 +14,7 @@ use xCAT::MsgUtils;
use xCAT::Utils;
use xCAT::Client;
use xCAT_plugin::notification;
use xCAT_monitoring::montbhandler;
#the list store the names of the monitoring plug-in and the file name and module names.
#the names are stored in the "name" column of the monitoring table.
@ -72,6 +73,9 @@ sub start {
#setup signal
$SIG{USR2}=\&handleMonSignal;
xCAT_monitoring::montbhandler->regMonitoringNotif();
#start monitoring for all the registered plug-ins in the monitoring table.
#better span a process so that it will not block the xcatd.
my $pid;
@ -92,20 +96,12 @@ sub start {
print "$_: @$retstat\n";
}
}
#register for nodelist table changes if not already registered
my $tab = xCAT::Table->new('notification');
my $regged=0;
if ($tab) {
(my $ref) = $tab->getAttribs({filename => qw(monitorctrl.pm)}, tables);
if ($ref and $ref->{tables}) {
$regged=1;
}
$tab->close();
if (keys(%PRODUCT_LIST) > 0) {
regNodelistNotif();
}
if (!$regged) {
xCAT_plugin::notification::regNotification([qw(monitorctrl.pm nodelist,monitoring -o a,u,d)]);
else {
unregNodelistNotif();
}
#print "child done\n";
@ -113,6 +109,62 @@ sub start {
}
}
#--------------------------------------------------------------------------------
=head3 regNodelistNotif
It registers this module in the notification table to watch for changes in
the nodelist table.
Arguments:
none
Returns:
0 for successful.
non-0 for not successful.
=cut
#--------------------------------------------------------------------------------
sub regNodelistNotif {
#register for nodelist table changes if not already registered
my $tab = xCAT::Table->new('notification');
my $regged=0;
if ($tab) {
(my $ref) = $tab->getAttribs({filename => qw(monitorctrl.pm)}, tables);
if ($ref and $ref->{tables}) {
$regged=1;
}
$tab->close();
}
if (!$regged) {
xCAT_plugin::notification::regNotification([qw(monitorctrl.pm nodelist -o a,d)]);
}
}
#--------------------------------------------------------------------------------
=head3 unregNodelistNotif
It un-registers this module in the notification table.
Arguments:
none
Returns:
0 for successful.
non-0 for not successful.
=cut
#--------------------------------------------------------------------------------
sub unregNodelistNotif {
my $tab = xCAT::Table->new('notification');
my $regged=0;
if ($tab) {
(my $ref) = $tab->getAttribs({filename => qw(monitorctrl.pm)}, tables);
if ($ref and $ref->{tables}) {
$regged=1;
}
$tab->close();
}
if ($regged) {
xCAT_plugin::notification::unregNotification([qw(monitorctrl.pm)]);
}
}
#-------------------------------------------------------------------------------
=head3 handleSignal
@ -172,6 +224,16 @@ sub handleMonSignal {
}
}
#registers or unregusters this module in the notification table for changes in
# the nodelist and monitoring tables.
if (keys(%PRODUCT_LIST) > 0) {
regNodelistNotif();
}
else {
unregNodelistNotif();
}
#setup the signal again
$SIG{USR2}=\&handleMonSignal;
@ -230,7 +292,8 @@ sub stop {
$ret{"Stop node status monitoring with $NODESTAT_MON_NAME"}=\@ret2;
}
xCAT_plugin::notification::unregNotification([qw(monitorctrl.pm)]);
xCAT_monitoring::montbhandler->unregMonitoringNotif();
unregNodelistNotif();
if (%ret) {
foreach(keys(%ret)) {
@ -309,7 +372,7 @@ sub startMonitoring {
#--------------------------------------------------------------------------------
sub startNodeStatusMonitoring {
my $pname=shift;
if ($pname =~ /xCAT_plugin::monitorctrl/) {
if ($pname =~ /xCAT_monitoring::monitorctrl/) {
$pname=shift;
}
@ -413,7 +476,7 @@ sub stopMonitoring {
#--------------------------------------------------------------------------------
sub stopNodeStatusMonitoring {
my $pname=shift;
if ($pname =~ /xCAT_plugin::monitorctrl/) {
if ($pname =~ /xCAT_monitoring::monitorctrl/) {
$pname=shift;
}
@ -472,18 +535,15 @@ sub stopNodeStatusMonitoring {
#--------------------------------------------------------------------------------
sub processTableChanges {
my $action=shift;
if ($action =~ /xCAT_plugin::monitorctrl/) {
if ($action =~ /xCAT_monitoring::monitorctrl/) {
$action=shift;
}
my $tablename=shift;
my $old_data=shift;
my $new_data=shift;
if ($tablename eq "nodelist") {
processNodelistTableChanges($action, $tablename, $old_data, $new_data);
} else {
processMonitoringTableChanges($action, $tablename, $old_data, $new_data);
}
processNodelistTableChanges($action, $tablename, $old_data, $new_data);
}
@ -501,7 +561,7 @@ sub processTableChanges {
#--------------------------------------------------------------------------------
sub processNodelistTableChanges {
my $action=shift;
if ($action =~ /xCAT_plugin::monitorctrl/) {
if ($action =~ /xCAT_monitoring::monitorctrl/) {
$action=shift;
}
#print "monitorctrl::processNodelistTableChanges action=$action\n";
@ -530,10 +590,10 @@ sub processNodelistTableChanges {
if ($action eq "a") {
if ($new_data) {
my $nodetype='';
my $groups='';
my $status='';
if (exists($new_data->{nodetype})) {$nodetype=$new_data->{nodetype};}
if (exists($new_data->{groups})) {$groups=$new_data->{groups};}
push(@nodenames, [$new_data->{node}, $nodetype, $groups]);
if (exists($new_data->{status})) {$status=$new_data->{status};}
push(@nodenames, [$new_data->{node}, $nodetype, $status]);
my $hierarchy=getMonServerWithInfo(\@nodenames);
#call each plug-in to add the nodes into the monitoring domain
@ -551,19 +611,19 @@ sub processNodelistTableChanges {
$colnames=$old_data->[0];
my $node_i=-1;
my $nodetype_i=-1;
my $groups_i=-1;
my $status_i=-1;
for ($i=0; $i<@$colnames; ++$i) {
if ($colnames->[$i] eq "node") {
$node_i=$i;
} elsif ($colnames->[$i] eq "nodetype") {
$nodetype_i=$i;
} elsif ($colnames->[$i] eq "groups") {
$groups_i=$i;
} elsif ($colnames->[$i] eq "status") {
$status_i=$i;
}
}
for (my $j=1; $j<@$old_data; ++$j) {
push(@nodenames, [$old_data->[$j]->[$node_i], $old_data->[$j]->[$nodetype_i], $old_data->[$j]->[$groups_i]]);
push(@nodenames, [$old_data->[$j]->[$node_i], $old_data->[$j]->[$nodetype_i], $old_data->[$j]->[$status_i]]);
}
if (@nodenames > 0) {
@ -608,9 +668,8 @@ sub processMonitoringTableChanges {
#--------------------------------------------------------------------------------
=head3 processNodeStatusChanges
This is the callback routine passed as a parameter to the startNodeStatusMon()
function of the monitoring plug-ins. This routine will be called by a
selected monitoring plug-in module to feed the node status back to xcat.
This routine will be called by
monitoring plug-in modules to feed the node status back to xcat.
(callback mode). This function will update the status column of the
nodelist table with the new node status.
Arguments:
@ -625,7 +684,7 @@ sub processMonitoringTableChanges {
sub processNodeStatusChanges {
#print "monitorctrl::processNodeStatusChanges called\n";
my $temp=shift;
if ($temp =~ /xCAT_plugin::monitorctrl/) {
if ($temp =~ /xCAT_monitoring::monitorctrl/) {
$temp=shift;
}
@ -753,13 +812,13 @@ sub refreshProductList {
=head3 getMonHierarchy
It gets the monnitoring server node for all the nodes within nodelist table.
The "monserver" attribute is used from the noderes table. If "monserver" is not defined
for a node, "xcatmaster" is used. If none is defined, use the local host.
for a node, "servicenode" is used. If none is defined, use the local host.
Arguments:
None.
Returns:
A hash reference keyed by the monitoring server nodes and each value is a ref to
an array of [nodes, nodetype] arrays monitored by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
an array of [nodes, nodetype, status] arrays monitored by the server. So the format is:
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
=cut
#--------------------------------------------------------------------------------
sub getMonHierarchy {
@ -767,53 +826,33 @@ sub getMonHierarchy {
#get all from nodelist table and noderes table
my $table=xCAT::Table->new("nodelist", -create =>0);
my @tmp1=$table->getAllAttribs(('node','nodetype', 'groups'));
my @tmp1=$table->getAllAttribs(('node','nodetype', 'status'));
my $table2=xCAT::Table->new("noderes", -create =>0);
my @tmp2=$table2->getAllAttribs(('node','monserver', 'xcatmaster'));
#get monserver for each node. use "monserver" attribute from noderes table, if not
#defined, use "xcatmaster". otherwise, use loca lhost.
#defined, use "servicenode". otherwise, use loca lhost.
my $host=hostname();
if (defined(@tmp1) && (@tmp1 > 0)) {
if (defined(@tmp2) && (@tmp2 > 0)) {
foreach(@tmp1) {
my $node=$_->{node};
my $groups=$_->{groups};
my $nodetype=$_->{nodetype};
my @group_array=();
if ($groups) {
@group_array=split(/,/, $groups);
}
my $monserver=$host;
foreach(@tmp2) {
my $node2=$_->{node};
if (($node2 eq $node) || (grep {$_ eq $node2} @group_array)) {
if ($_->{monserver}) {
$monserver=$_->{monserver};
}
elsif ($_->{xcatmaster}) {
$monserver=$_->{xcatmaster};
}
}
}
if (exists($ret->{$monserver})) {
my $pa=$ret->{$monserver};
push(@$pa, [$node, $nodetype]);
}
else {
$ret->{$monserver}=[[$node, $nodetype]];
}
foreach(@tmp1) {
my $node=$_->{node};
my $status=$_->{status};
my $nodetype=$_->{nodetype};
my $monserver=$host;
my $tmp2=$table2->getNodeAttribs($node, ['monserver', 'servicenode']);
if (defined($tmp2) && ($tmp2)) {
if ($tmp2->{monserver}) { $monserver=$tmp2->{monserver}; }
elsif ($tmp2->{servicenode}) { $monserver=$tmp2->{servicenode}; }
}
if (exists($ret->{$monserver})) {
my $pa=$ret->{$monserver};
push(@$pa, [$node, $nodetype, $status]);
}
else {
$ret->{$monserver}=[[$node, $nodetype, $status]];
}
}
else {
#no entried in noderes table, use local host as the monserver for all the nodes
my $nodes=[];
foreach(@tmp1) {
push(@$nodes, [$_->{node}, $nodetype]);
}
$ret->{$host}=$nodes;
}
}
$table->close();
$table2->close();
@ -824,17 +863,17 @@ sub getMonHierarchy {
=head3 getMonServerWithInfo
It gets the monnitoring server node for each of the nodes from the input.
The "monserver" attribute is used from the noderes table. If "monserver" is not defined
for a node, "xcatmaster" is used. If none is defined, use the local host as the
for a node, "servicenode" is used. If none is defined, use the local host as the
the monitoring server. The difference of this function from the getMonServer function
is that the input of the nodes have 'node', 'nodetype' and 'groups' info.
is that the input of the nodes have 'node', 'nodetype' and 'status' info.
The other one just has 'node'. The
names.
Arguments:
nodes: An array ref. Each element is of the format: [node, nodetype, groups]
nodes: An array ref. Each element is of the format: [node, nodetype, status]
Returns:
A hash reference keyed by the monitoring server nodes and each value is a ref to
an array of [nodes, nodetype] arrays monitored by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
an array of [nodes, nodetype, status] arrays monitored by the server. So the format is:
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
=cut
#--------------------------------------------------------------------------------
sub getMonServerWithInfo {
@ -846,32 +885,21 @@ sub getMonServerWithInfo {
#print "getMonServerWithInfo called with @in_nodes\n";
#get all from the noderes table
my $table2=xCAT::Table->new("noderes", -create =>0);
my @tmp2=$table2->getAllAttribs(('node','monserver', 'xcatmaster'));
my $host=hostname();
foreach (@in_nodes) {
my $node=$_->[0];
my $nodetype=$_->[1];
my $groups=$_->[2];
my @group_array=();
if ($groups) {
@group_array=split(/,/, $groups);
}
my $status=$_->[2];
my $monserver=$host;
if (defined(@tmp2) && (@tmp2 > 0)) {
foreach(@tmp2) {
my $node2=$_->{node};
if (($node2 eq $node) || (grep {$_ eq $node2} @group_array)) {
if ($_->{monserver}) {
$monserver=$_->{monserver};
}
elsif ($_->{xcatmaster}) {
$monserver=$_->{xcatmaster};
}
}
}
}
my $tmp2=$table2->getNodeAttribs($node, ['monserver', 'servicenode']);
if (defined($tmp2) && ($tmp2)) {
if ($tmp2->{monserver}) { $monserver=$tmp2->{monserver}; }
elsif ($tmp2->{servicenode}) { $monserver=$tmp2->{servicenode}; }
}
if (exists($ret->{$monserver})) {
my $pa=$ret->{$monserver};
push(@$pa, [$node, $nodetype]);
@ -890,14 +918,14 @@ sub getMonServerWithInfo {
=head3 getMonServer
It gets the monnitoring server node for each of the nodes from the input.
The "monserver" attribute is used from the noderes table. If "monserver" is not defined
for a node, "xcatmaster" is used. If none is defined, use the local host as the
for a node, "servicenode" is used. If none is defined, use the local host as the
the monitoring server.
Arguments:
nodes: An array ref of nodes.
Returns:
A hash reference keyed by the monitoring server nodes and each value is a ref to
an array of [nodes, nodetype] arrays monitored by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
an array of [nodes, nodetype, status] arrays monitored by the server. So the format is:
{monserver1=>[['node1', 'osi', active'], ['node2', 'switch', booting']...], ...}
=cut
#--------------------------------------------------------------------------------
sub getMonServer {
@ -908,42 +936,29 @@ sub getMonServer {
#get all from nodelist table and noderes table
my $table=xCAT::Table->new("nodelist", -create =>0);
my $table2=xCAT::Table->new("noderes", -create =>0);
my @tmp2=$table2->getAllAttribs(('node','monserver', 'xcatmaster'));
my $host=hostname();
foreach (@in_nodes) {
my @tmp1=$table->getAttribs({'node'=>$_}, ('node', 'nodetype', 'groups'));
my @tmp1=$table->getAttribs({'node'=>$_}, ('node', 'nodetype', 'status'));
if (defined(@tmp1) && (@tmp1 > 0)) {
my $node=$_;
my $groups=$tmp1[0]->{groups};
my $status=$tmp1[0]->{status};
my $nodetype=$tmp1[0]->{nodetype};
my @group_array=();
if ($groups) {
@group_array=split(/,/, $groups);
}
my $monserver=$host;
if (defined(@tmp2) && (@tmp2 > 0)) {
foreach(@tmp2) {
my $node2=$_->{node};
if (($node2 eq $node) || (grep {$_ eq $node2} @group_array)) {
if ($_->{monserver}) {
$monserver=$_->{monserver};
}
elsif ($_->{xcatmaster}) {
$monserver=$_->{xcatmaster};
}
}
}
}
my $tmp2=$table2->getNodeAttribs($node, ['monserver', 'servicenode']);
if (defined($tmp2) && ($tmp2)) {
if ($tmp2->{monserver}) { $monserver=$tmp2->{monserver}; }
elsif ($tmp2->{servicenode}) { $monserver=$tmp2->{servicenode}; }
}
if (exists($ret->{$monserver})) {
my $pa=$ret->{$monserver};
push(@$pa, [$node, $nodetype]);
push(@$pa, [$node, $nodetype, $status]);
}
else {
$ret->{$monserver}=[ [$node,$nodetype] ];
$ret->{$monserver}=[ [$node,$nodetype, $status] ];
}
}
}

View File

@ -0,0 +1,124 @@
#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_monitoring::montbhandler;
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl";
use xCAT::Table;
use xCAT::MsgUtils;
use xCAT::Utils;
use xCAT_plugin::notification;
use xCAT_monitoring::monitorctrl;
1;
#-------------------------------------------------------------------------------
=head1 xCAT_monitoring:montbhandler
=head2 Package Description
xCAT monitoring table handler module. This is a helper module for monitorctrl module
becuase the notification infrastructure does not allow a module to register more
than one callbacks. This module registers and unregisters notification to watch for
the changes in the monitoring tables. When changes occurrs, it forward the info
back to monitorctrl module for handling.
=cut
#-------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
=head3 regMonitoringNotif
It registers this module in the notification table to watch for changes in
the monitoring table.
Arguments:
none
Returns:
0 for successful.
non-0 for not successful.
=cut
#--------------------------------------------------------------------------------
sub regMonitoringNotif {
#register for nodelist table changes if not already registered
my $tab = xCAT::Table->new('notification');
my $regged=0;
if ($tab) {
(my $ref) = $tab->getAttribs({filename => qw(montbhandler.pm)}, tables);
if ($ref and $ref->{tables}) {
$regged=1;
}
$tab->close();
}
if (!$regged) {
xCAT_plugin::notification::regNotification([qw(montbhandler.pm monitoring -o a,u,d)]);
}
}
#--------------------------------------------------------------------------------
=head3 unregMonitoringNotif
It un-registers this module in the notification table.
Arguments:
none
Returns:
0 for successful.
non-0 for not successful.
=cut
#--------------------------------------------------------------------------------
sub unregMonitoringNotif {
my $tab = xCAT::Table->new('notification');
my $regged=0;
if ($tab) {
(my $ref) = $tab->getAttribs({filename => qw(montbhandler.pm)}, tables);
if ($ref and $ref->{tables}) {
$regged=1;
}
$tab->close();
}
if ($regged) {
xCAT_plugin::notification::unregNotification([qw(montbhandler.pm)]);
}
}
#--------------------------------------------------------------------------------
=head3 processTableChanges
It is called by the NotifHander module
when the monitoring tables get changed. If a plug-in
is added or removed from the monitoring table. this function will start
or stop the plug-in for monitoing the xCAT cluster.
Arguments:
action - table action. It can be d for rows deleted, a for rows added
or u for rows updated.
tablename - string. The name of the DB table whose data has been changed.
old_data - an array reference of the old row data that has been changed.
The first element is an array reference that contains the column names.
The rest of the elelments are also array references each contains
attribute values of a row.
It is set when the action is u or d.
new_data - a hash refernce of new row data; only changed values are present
in the hash. It is keyed by column names.
It is set when the action is u or a.
Returns:
0 for successful.
non-0 for not successful.
=cut
#--------------------------------------------------------------------------------
sub processTableChanges {
my $action=shift;
if ($action =~ /xCAT_plugin::montbhandler/) {
$action=shift;
}
my $tablename=shift;
my $old_data=shift;
my $new_data=shift;
xCAT_monitoring::monitorctrl->processMonitoringTableChanges($action, $tablename, $old_data, $new_data);
}

View File

@ -33,9 +33,9 @@ package xCAT_monitoring::templatemon;
in the xCAT cluster.
Arguments:
monservers --A hash reference keyed by the monitoring server nodes
and each value is a ref to an array of [nodes, nodetype] arrays
and each value is a ref to an array of [nodes, nodetype, status] arrays
monitored by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
Returns:
(return code, message)
=cut
@ -52,8 +52,8 @@ sub start {
print " monitoring server: $_\n";
my $mon_nodes=$monservers->{$_};
foreach(@$mon_nodes) {
$node_pair=$_;
print " node=$node_pair->[0], nodetype=$node_pair->[1]\n";
my $node_info=$_;
print " node=$node_info->[0], nodetype=$node_info->[1], status=$node_info->[2]\n";
}
}
@ -111,9 +111,9 @@ sub supportNodeStatusMon {
to xCAT.
Arguments:
monservers --A hash reference keyed by the monitoring server nodes
and each value is a ref to an array of [nodes, nodetype] arrays
and each value is a ref to an array of [nodes, nodetype, status] arrays
monitored by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
Returns:
(return code, message)
@ -131,8 +131,8 @@ sub startNodeStatusMon {
print " monitoring server: $_\n";
my $mon_nodes=$monservers->{$_};
foreach(@$mon_nodes) {
$node_pair=$_;
print " node=$node_pair->[0], nodetype=$node_pair->[1]\n";
my $node_info=$_;
print " node=$node_info->[0], nodetype=$node_info->[1], status=$node_info->[2]\n";
}
}
@ -164,9 +164,9 @@ sub stopNodeStatusMon {
to the xCAT cluster. It should add the nodes into the product for monitoring.
Arguments:
nodes --nodes to be added. It is a hash reference keyed by the monitoring server
nodes and each value is a ref to an array of [nodes, nodetype] arrays monitored
nodes and each value is a ref to an array of [nodes, nodetype, status] arrays monitored
by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'bboting']...], ...}
Returns:
none
=cut
@ -182,8 +182,8 @@ sub addNodes {
print " monitoring server: $_\n";
my $mon_nodes=$noderef->{$_};
foreach(@$mon_nodes) {
$node_pair=$_;
print " node=$node_pair->[0], nodetype=$node_pair->[1]\n";
my $node_info=$_;
print " node=$node_info->[0], nodetype=$node_info->[1], status=$node_info->[2]\n";
}
}
@ -197,9 +197,9 @@ sub addNodes {
from the xCAT cluster. It should remove the nodes from the product for monitoring.
Arguments:
nodes --nodes to be removed. It is a hash reference keyed by the monitoring server
nodes and each value is a ref to an array of [nodes, nodetype] arrays monitored
nodes and each value is a ref to an array of [nodes, nodetype, status] arrays monitored
by the server. So the format is:
{monserver1=>[['node1', 'osi'], ['node2', 'switch']...], ...}
{monserver1=>[['node1', 'osi', 'active'], ['node2', 'switch', 'booting']...], ...}
Returns:
none
=cut
@ -215,8 +215,8 @@ sub removeNodes {
print " monitoring server: $_\n";
my $mon_nodes=$noderef->{$_};
foreach(@$mon_nodes) {
$node_pair=$_;
print " node=$node_pair->[0], nodetype=$node_pair->[1]\n";
my $node_info=$_;
print " node=$node_info->[0], nodetype=$node_info->[1], status=$node_info->[2]\n";
}
}