xcat-core/xCAT-server/lib/xcat/plugins/monctrlcmds.pm
2008-11-11 17:37:51 +00:00

1550 lines
47 KiB
Perl

#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT_plugin::monctrlcmds;
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl";
use strict;
use xCAT::NodeRange;
use xCAT::Table;
use xCAT::MsgUtils;
use xCAT_monitoring::monitorctrl;
use xCAT::Utils;
use Sys::Hostname;
1;
#-------------------------------------------------------------------------------
=head1 xCAT_plugin:monctrlcmds
=head2 Package Description
xCAT monitoring control commands plugini module. This modules handles
monitoring related commands.
=cut
#-------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
=head3 handled_commands
It returns a list of commands handled by this plugin.
Arguments:
none
Returns:
a list of commands.
=cut
#--------------------------------------------------------------------------------
sub handled_commands {
return {
monstart => "monctrlcmds",
monstop => "monctrlcmds",
monls => "monctrlcmds",
monadd => "monctrlcmds",
monrm => "monctrlcmds",
moncfg => "monctrlcmds",
mondecfg => "monctrlcmds",
}
}
#-------------------------------------------------------
=head3 preprocess_request
Check and setup for hierarchy
=cut
#-------------------------------------------------------
sub preprocess_request
{
my $req = shift;
my $callback = shift;
my $command = $req->{command}->[0];
if ($req->{_xcatdest}) { return [$req]; } #exit if preprocessed
my $args=$req->{arg};
my @requests=();
if (($command eq "monstart") || ($command eq "monstop") || ($command eq "moncfg") || ($command eq "mondecfg") ) {
my @a_ret; #(0, $modulename, $nodestatutmon, $scope, \@nodes)
if ($command eq "monstart") {
@a_ret=preprocess_monstart($args, $callback);
} elsif ($command eq "monstop") {
@a_ret=preprocess_monstop($args, $callback);
} elsif ($command eq "moncfg") {
@a_ret=preprocess_moncfg($args, $callback);
} else {
@a_ret=preprocess_mondecfg($args, $callback);
}
if ($a_ret[0] != 0) {
$req = {};
return;
} else {
my $allnodes=$a_ret[4];
print "allnodes=@$allnodes\n";
my $pname=$a_ret[1];
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
my $module_name="xCAT_monitoring::$pname";
undef $SIG{CHLD};
#initialize and start monitoring
no strict "refs";
my $mon_hierachy;
if (defined(${$module_name."::"}{getNodesMonServers})) {
$mon_hierachy = ${$module_name."::"}{getNodesMonServers}->($allnodes, $callback);
} else {
$mon_hierachy=xCAT_monitoring::monitorctrl->getNodeMonServerPair($allnodes, 1);
}
my @mon_servers=keys(%$mon_hierachy);
my @hostinfo=xCAT::Utils->determinehostname();
#print "hostinfo=@hostinfo\n";
my $isSV=xCAT::Utils->isServiceNode();
my %iphash=();
foreach(@hostinfo) {$iphash{$_}=1;}
if (!$isSV) { $iphash{'noservicenode'}=1;}
foreach (@mon_servers) {
#service node come in pairs, the first one is the monserver adapter that facing the mn,
# the second one is facing the cn. we use the first one here
my @server_pair=split(',', $_);
my $sv=$server_pair[0];
my $mon_nodes=$mon_hierachy->{$_};
if ((!$mon_nodes) || (@$mon_nodes ==0)) { next; }
print "sv=$sv, nodes=@$mon_nodes\n";
my $reqcopy = {%$req};
if (! $iphash{$sv}) {
if ($isSV) { next; } #if the command is issued on the monserver,
# only handle its children.
$reqcopy->{'_xcatdest'}=$sv;
my $rsp2={};
$rsp2->{data}->[0]="sending request to $sv...";
$callback->($rsp2);
}
push @{$reqcopy->{module}}, $a_ret[1];
push @{$reqcopy->{nodestatmon}}, $a_ret[2];
push @{$reqcopy->{scope}}, $a_ret[3];
push @{$reqcopy->{nodeinfo}}, join(',', @$mon_nodes);
push @requests, $reqcopy;
}
}
} else {
my $reqcopy = {%$req};
push @requests, $reqcopy;
}
return \@requests;
}
#--------------------------------------------------------------------------------
=head3 process_request
It processes the monitoring control commands.
Arguments:
request -- a hash table which contains the command name and the arguments.
callback -- a callback pointer to return the response to.
Returns:
0 for success. The output is returned through the callback pointer.
1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub process_request {
use Getopt::Long;
# options can be bundled up like -vV
Getopt::Long::Configure("bundling") ;
$Getopt::Long::ignorecase=0;
#print "process_request get called\n";
my $request = shift;
my $callback = shift;
my $command = $request->{command}->[0];
my $args=$request->{arg};
my $doreq = shift;
if ($command eq "monstart") {
return monstart($request, $callback, $doreq);
}
elsif ($command eq "monstop") {
return monstop($request, $callback, $doreq);
}
elsif ($command eq "monls") {
return monls($request, $callback, $doreq);
}
elsif ($command eq "monadd") {
return monadd($request, $callback, $doreq);
}
elsif ($command eq "monrm") {
return monrm($request, $callback, $doreq);
}
elsif ($command eq "moncfg") {
return moncfg($request, $callback, $doreq);
}
elsif ($command eq "mondecfg") {
return mondecfg($request, $callback, $doreq);
} else {
my $rsp={};
$rsp->{data}->[0]= "unsupported command: $command.";
$callback->($rsp);
return 1;
}
}
#--------------------------------------------------------------------------------
=head3 preprocess_monstart
This function handles the syntax checking for monstart command,
turn on the given monitoring plug-in to the 'monitoring' table.
Arguments:
callback - the pointer to the callback function.
args - The format of the args is:
[-h|--help|-v|--version] or
name [noderange] [-r|--remote]
where
name is the monitoring plug-in name. For example: rmcmon.
The specified plug-in will be invoked for monitoring the xCAT cluster.
noderange a range of nodes to be monitored. Default is all.
-r|--remote indicates that both monservers and the nodes need to be called to start
the monitoring. The defaults is monservers only.
Returns:
(0, $modulename, $nodestatutmon, $scope, \@nodes) for success. scope is the scope of the
actions. 1 means monervers only, 2 means both nodes and monservers.
(1, "") for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub preprocess_monstart
{
my $args=shift;
my $callback=shift;
if (xCAT::Utils->isServiceNode()) {
my $rsp={};
$rsp->{data}->[0]= "This command is not supported on a service node.";
$callback->($rsp);
return (1, "");
}
# subroutine to display the usage
sub monstart_usage
{
my $cb=shift;
my $rsp={};
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " monstart name [noderange] [-r|--remote]";
$rsp->{data}->[2]= " monstart [-h|--help|-v|--version]";
$rsp->{data}->[3]= " name is the name of the monitoring plug-in module to be invoked.";
$rsp->{data}->[4]= " Use 'monls -a' command to list all the monitoring plug-in names.";
$rsp->{data}->[5]= " noderange is a range of nodes to be monitored. The default is all nodes.";
$rsp->{data}->[6]= " -r|--remote indicates that both monservers and the nodes need to be called\n to start the monitoring. The default is monservers only.";
$cb->($rsp);
}
@ARGV=();
if ($args) { @ARGV=@{$args};}
my $settings;
# parse the options
if(!GetOptions(
'h|help' => \$::HELP,
'v|version' => \$::VERSION,
'r|remote' => \$::REMOTE,))
{
&monstart_usage($callback);
return (1, "");
}
# display the usage if -h or --help is specified
if ($::HELP) {
&monstart_usage($callback);
return 1;
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my $rsp={};
$rsp->{data}->[0]= xCAT::Utils->Version();
$callback->($rsp);
return (1, "");
}
my $pname="";
my $scope=0; #set it to 0 instead of 1 because it will be distributed to monservers.
my @nodes=();
my $nodestatmon=0;
if ($::REMOTE) { $scope=2; }
if (@ARGV < 1)
{
&monstart_usage($callback);
return (1, "");
}
else {
#@product_names=split(/,/, $ARGV[0]);
$pname=$ARGV[0];
if (@ARGV > 1) {
my $noderange=$ARGV[1];
@nodes = noderange($noderange);
if (nodesmissed) {
my $rsp={};
$rsp->{data}->[0]= "Invalid nodes in noderange:".join(',',nodesmissed);
$callback->($rsp);
return (1, "");
}
}
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
if (!-e $file_name) {
my $rsp={};
$rsp->{data}->[0]="File $file_name does not exist.";
$callback->($rsp);
return (1, "");
} else {
#load the module in memory
eval {require($file_name)};
if ($@) {
my $rsp={};
$rsp->{data}->[0]="The file $file_name has compiling errors:\n$@\n";
$callback->($rsp);
return (1, "");
}
}
}
my $table=xCAT::Table->new("monitoring", -create => 1,-autocommit => 1);
if ($table) {
my $found=0;
my $tmp1=$table->getAllEntries();
if (defined($tmp1) && (@$tmp1 > 0)) {
foreach(@$tmp1) {
if ($pname eq $_->{name}) {
$found=1;
if ($_->{disable} !~ /0|NO|No|no|N|n/) {
my %key_col = (name=>$pname);
my %tb_cols=(disable=>"0");
$table->setAttribs(\%key_col, \%tb_cols);
}
if ($_->{nodestatmon} =~ /1|Yes|yes|YES|Y|y/) { $nodestatmon=1;}
last;
}
}
}
if (!$found) {
my $rsp={};
$rsp->{data}->[0]="$pname has not been added to the monitoring table. Please run 'monadd' command to add.";
$callback->($rsp);
$table->close();
return (1, "");
}
$table->close();
} else {
my $rsp={};
$rsp->{data}->[0]="Failed to open the monitoring table.";
$callback->($rsp);
return (1, "");
}
return (0, $pname, $nodestatmon, $scope, \@nodes);
}
#--------------------------------------------------------------------------------
=head3 monstart
This function calls moniutoring control to start the monitoring and node
status monitoring for the given plug-in module.
Arguments:
request -- pointer to a hash with keys are command, module and nodestatmon.
callback - the pointer to the callback function.
Returns:
0 for success. The output is returned through the callback pointer.
1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monstart {
my $request=shift;
my $callback=shift;
my $pname=$request->{module}->[0];
my $nodestatmon=$request->{nodestatmon}->[0];
my $scope=$request->{scope}->[0];
my $nodeinfo=$request->{nodeinfo}->[0];
my @nodes=split(',', $nodeinfo);
print "monstart get called: pname=$pname\nnodestatmon=$nodestatmon\nnodeinfo=$nodeinfo\nscope=$scope\n";
xCAT_monitoring::monitorctrl->startMonitoring([$pname], \@nodes, $scope, $callback);
if ($nodestatmon) {
xCAT_monitoring::monitorctrl->startNodeStatusMonitoring($pname, \@nodes, $scope, $callback);
}
return;
}
#--------------------------------------------------------------------------------
=head3 preprocess_monstop
This function unregisters the given monitoring plug-in from the 'monitoring' table.
Arguments:
callback - the pointer to the callback function.
args - The format of the args is:
[-h|--help|-v|--version] or
name [noderange] [-r|--remote]
name
where
name is the monitoring plug-in name. For example: rmcmon.
The specified plug-in will be stoped for monitoring the xCAT cluster.
noderange a range of nodes. Default is all.
-r|--remote indicates that both monservers and the nodes need to be called to stop
the monitoring. The defaults is monservers only.
Returns:
(0, $modulename, $nodestatutmon, $scope, \@nodes) for success. scope is the scope of the
actions. 1 means monervers only, 2 means both nodes and monservers.
(1, "") for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub preprocess_monstop
{
my $args=shift;
my $callback=shift;
if (xCAT::Utils->isServiceNode()) {
my $rsp={};
$rsp->{data}->[0]= "This command is not supported on a service node.";
$callback->($rsp);
return (1, "");
}
# subroutine to display the usage
sub monstop_usage
{
my $cb=shift;
my $rsp={};
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " monstop name [noderange] [-r|--remote]";
$rsp->{data}->[2]= " monstop [-h|--help|-v|--version]";
$rsp->{data}->[3]= " name is the name of the monitoring plug-in module registered in the monitoring table.";
$cb->($rsp);
}
@ARGV=();
if ($args) { @ARGV=@{$args};}
# parse the options
if(!GetOptions(
'h|help' => \$::HELP,
'r|remote' => \$::REMOTE,
'v|version' => \$::VERSION,))
{
&monstop_usage($callback);
return (1, "");
}
# display the usage if -h or --help is specified
if ($::HELP) {
&monstop_usage($callback);
return (1, "");
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my $rsp={};
$rsp->{data}->[0]= xCAT::Utils->Version();;
$callback->($rsp);
return (1, "");
}
my $pname="";
my $scope=0;
my @nodes=();
my $nodestatmon=0;
if ($::REMOTE) { $scope=2;}
if (@ARGV < 1)
{
&monstop_usage($callback);
return (1, "");
}
else {
$pname=$ARGV[0];
if (@ARGV > 1) {
my $noderange=$ARGV[1];
@nodes = noderange($noderange);
if (nodesmissed) {
my $rsp={};
$rsp->{data}->[0]= "Invalid nodes in noderange:".join(',',nodesmissed);
$callback->($rsp);
return (1, "");
}
}
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
if (!-e $file_name) {
my $rsp={};
$rsp->{data}->[0]="File $file_name does not exist.";
$callback->($rsp);
return (1, "");
} else {
#load the module in memory
eval {require($file_name)};
if ($@) {
my $rsp={};
$rsp->{data}->[0]="The file $file_name has compiling errors:\n$@\n";
$callback->($rsp);
return (1, "");
}
}
}
my $table=xCAT::Table->new("monitoring", -create => 1,-autocommit => 1);
if ($table) {
my $found=0;
my $tmp1=$table->getAllEntries();
if (defined($tmp1) && (@$tmp1 > 0)) {
foreach(@$tmp1) {
if ($pname eq $_->{name}) {
$found=1;
if ($_->{disable} =~ /0|NO|No|no|N|n/) {
my %key_col = (name=>$pname);
my %tb_cols=(disable=>"1");
$table->setAttribs(\%key_col, \%tb_cols);
}
if ($_->{nodestatmon} =~ /1|Yes|yes|YES|Y|y/) { $nodestatmon=1;}
last;
}
}
}
if (!$found) {
my $rsp={};
$rsp->{data}->[0]="$pname cannot be found in the monitoring table.";
$callback->($rsp);
$table->close();
return (1, "");
}
$table->close();
} else {
my $rsp={};
$rsp->{data}->[0]="Failed to open the monitoring table.";
$callback->($rsp);
return (1, "");
}
return (0, $pname, $nodestatmon, $scope, \@nodes);
}
#--------------------------------------------------------------------------------
=head3 monstop
This function calls moniutoring control to stop the monitoring and node
status monitoring for the given plug-in module.
Arguments:
request -- pointer to a hash with keys are command, module and nodestatmon.
callback - the pointer to the callback function.
Returns:
0 for success. The output is returned through the callback pointer.
1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monstop {
my $request=shift;
my $callback=shift;
my $pname=$request->{module}->[0];
my $nodestatmon=$request->{nodestatmon}->[0];
my $scope=$request->{scope}->[0];
my $nodeinfo=$request->{nodeinfo}->[0];
my @nodes=split(',', $nodeinfo);
print "monstop get called: pname=$pname\nnodestatmon=$nodestatmon\nnodeinfo=@nodes\nscope=$scope\n";
if ($nodestatmon) {
xCAT_monitoring::monitorctrl->stopNodeStatusMonitoring($pname, \@nodes, $scope, $callback);
}
xCAT_monitoring::monitorctrl->stopMonitoring([$pname], \@nodes, $scope, $callback);
return;
}
#--------------------------------------------------------------------------------
=head3 monls
This function list the monitoring plug-in module names, status and description.
Arguments:
callback - the pointer to the callback function.
args - The format of the args is:
[-h|--help|-v|--version] or
[name] [-a|all] [-d|--description]
Returns:
0 for success. The output is returned through the callback pointer.
1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monls {
my $request = shift;
my $callback = shift;
my $args=$request->{arg};
my $doreq = shift;
# subroutine to display the usage
sub monls_usage
{
my $cb=shift;
my $rsp={};
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " monls name [-d|--description]";
$rsp->{data}->[2]= " monls [-a|--all] [-d|--description]";
$rsp->{data}->[3]= " monls [-h|--help|-v|--version]";
$rsp->{data}->[4]= " name is the name of the monitoring plug-in module.";
$cb->($rsp);
}
@ARGV=();
if ($args) {
@ARGV=@{$args};
}
# parse the options
if(!GetOptions(
'h|help' => \$::HELP,
'v|version' => \$::VERSION,
'a|all' => \$::ALL,
'd|discription' => \$::DESC))
{
&monls_usage($callback);
return;
}
# display the usage if -h or --help is specified
if ($::HELP) {
&monls_usage($callback);
return;
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my $rsp={};
$rsp->{data}->[0]= xCAT::Utils->Version();
$callback->($rsp);
return;
}
my $usetab=0;
my %names=();
my $plugin_dir="$::XCATROOT/lib/perl/xCAT_monitoring";
if (@ARGV > 0)
{
$names{$ARGV[0]}=0;
}
else {
if ($::ALL) {
#get all the module names from /opt/xcat/lib/perl/XCAT_monitoring directory
my @plugins=glob($plugin_dir."/*.pm");
foreach (@plugins) {
/.*\/([^\/]*).pm$/;
$names{$1}=0;
}
# remove 2 files that are not plug-ins
delete($names{monitorctrl});
delete($names{montbhandler});
}
else {
$usetab=1;
}
}
#get the list from the table
my $table=xCAT::Table->new("monitoring", -create =>1);
if ($table) {
my $tmp1=$table->getAllEntries();
if (defined($tmp1) && (@$tmp1 > 0)) {
foreach(@$tmp1) {
my $pname=$_->{name};
if (($usetab) || exists($names{$pname})) {
$names{$pname}=1;
#find out the monitoring plugin file and module name for the product
my $rsp={};
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
my $module_name="xCAT_monitoring::$pname";
#load the module in memory
eval {require($file_name)};
if ($@) {
$rsp->{data}->[0]="$pname: The file $file_name cannot be located or has compiling errors.";
$callback->($rsp);
next;
} else {
no strict "refs";
if (! defined(${$module_name."::"}{start})) { next; }
}
my $monnode=0;
my $disable=1;
if ($_->{nodestatmon} =~ /1|Yes|yes|YES|Y|y/) { $monnode=1; }
if ($_->{disable} =~ /0|NO|No|no|N|n/) { $disable=0; }
if ($disable) { $monnode=0; }
$rsp->{data}->[0]="$pname\t\t".
($disable ? "not-monitored" : "monitored") .
($monnode ? "\tnode-status-monitored" : "");
if ($::DESC) { getModuleDescription($rsp, $module_name); }
$callback->($rsp);
}
} #foreach
}
$table->close();
}
#now handle the ones that are not in the table
foreach(keys(%names)) {
my $pname=$_;
if (! $names{$pname}) {
my $rsp={};
#find out the monitoring plugin file and module name for the product
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
my $module_name="xCAT_monitoring::$pname";
#load the module in memory
eval {require($file_name)};
if ($@) {
$rsp->{data}->[0]="$pname: The file $file_name cannot be located or has compiling errors.";
$callback->($rsp);
next;
} else {
no strict "refs";
if (! defined(${$module_name."::"}{start})) { next; }
}
$rsp->{data}->[0]="$pname\t\tnot-monitored";
if ($::DESC) {
getModuleDescription($rsp, $module_name);
}
$callback->($rsp);
}
}
return;
}
#--------------------------------------------------------------------------------
=head3 getModuleDescription
This function gets description, postscripts and other info from the
the given monitoring plug_in and stored it in the given hash.
Arguments:
Returns:
0 for success.
1. for unsuccess.
=cut
#--------------------------------------------------------------------------------
sub getModuleDescription {
my $rsp=shift;
my $module_name=shift;
no strict "refs";
#description
if (defined(${$module_name."::"}{getDescription})) {
$rsp->{data}->[1]=${$module_name."::"}{getDescription}->();
} else {
$rsp->{data}->[1]=" No description available.";
}
#postscripts
$rsp->{data}->[2] = " Postscripts:\n";
if (defined(${$module_name."::"}{getPostscripts})) {
my $desc=${$module_name."::"}{getPostscripts}->();
my @pn=keys(%$desc);
if (@pn>0) {
foreach my $group (@pn) {
$rsp->{data}->[2] .= " $group: " . $desc->{$group};
}
} else { $rsp->{data}->[2] .= " None";}
} else { $rsp->{data}->[2] .= " None";}
#support node status monitoring
$rsp->{data}->[3] = " Support node status monitoring:\n";
my $snodestatusmon=0;
if (defined(${$module_name."::"}{supportNodeStatusMon})) {
$snodestatusmon=${$module_name."::"}{supportNodeStatusMon}->();
}
if ($snodestatusmon) { $rsp->{data}->[3] .= " Yes\n";}
else { $rsp->{data}->[3] .= " No\n"; }
return 0;
}
#--------------------------------------------------------------------------------
=head3 monadd
This function adds the given module name into the monitoring table and
sets the postsctipts in the postsctipts table. It also sets the given
settings into the monsetting table.
Arguments:
request -- a hash table which contains the command name and the arguments.
callback - the pointer to the callback function.
args - The format of the args is:
[-h|--help|-v|--version] or
name [-n|--nodestatmon] [-s|--settings ...]
where
name is the monitoring plug-in name. For example: rmcmon.
The specified plug-in will be registered and invoked
for monitoring the xCAT cluster.
-n|--nodestatmon indicates that this plug-in will be used for feeding the node liveness
status to the xCAT nodelist table. If not specified, the plug-in will not be used
for feeding node status to xCAT.
-s|--settings settings are used by the plug-in to customize it behavor.
Returns:
0 for success. The output is returned through the callback pointer.
1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monadd {
my $request = shift;
my $callback = shift;
my $args=$request->{arg};
my $doreq = shift;
# subroutine to display the usage
sub monadd_usage
{
my $cb=shift;
my $rsp={};
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " monadd name [-n|--nodestatmon] [-s|--settings settings]";
$rsp->{data}->[2]= " monadd [-h|--help|-v|--version]";
$rsp->{data}->[3]= " name is the name of the monitoring plug-in module to be added.";
$rsp->{data}->[4]= " Use 'monls -a' command to list all the monitoring plug-in names.";
$rsp->{data}->[5]= " settings is used by the monitoring plug-in to customize its behavior.";
$rsp->{data}->[6]= " Format: [key1=value1],[key2=value2]... ";
$rsp->{data}->[7]= " Please note that the square brackets are needed. ";
$rsp->{data}->[7]= " Use 'monls name -d' command to look for the possible settings for a plug-in.";
$rsp->{data}->[8]= " Example: monadd xcatmon -n -s [ping-interval=10]";
$cb->($rsp);
}
@ARGV=();
if ($args) { @ARGV=@{$args};}
my $settings;
# parse the options
if(!GetOptions(
'h|help' => \$::HELP,
'v|version' => \$::VERSION,
'n|nodestatmon' => \$::NODESTATMON,
's|settings=s' => \$settings))
{
&monadd_usage($callback);
return 1;
}
# display the usage if -h or --help is specified
if ($::HELP) {
&monadd_usage($callback);
return 1;
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my $rsp={};
$rsp->{data}->[0]= xCAT::Utils->Version();
$callback->($rsp);
return 1;
}
#my @product_names;
my $pname;
my $nodestatmon=0;
if (@ARGV < 1)
{
&monadd_usage($callback);
return 1;
}
else {
#@product_names=split(/,/, $ARGV[0]);
$pname=$ARGV[0];
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
if (!-e $file_name) {
my $rsp={};
$rsp->{data}->[0]="File $file_name does not exist.";
$callback->($rsp);
return 1;
} else {
#load the module in memory
eval {require($file_name)};
if ($@) {
my $rsp={};
$rsp->{data}->[0]="The file $file_name has compiling errors:\n$@\n";
$callback->($rsp);
return 1;
}
}
}
my $table=xCAT::Table->new("monitoring", -create =>1);
if ($table) {
my $tmp1=$table->getAllEntries();
if (defined($tmp1) && (@$tmp1 > 0)) {
foreach(@$tmp1) {
my $name=$_->{name};
if ($name eq $pname) {
my $rsp={};
$rsp->{data}->[0]="$pname has already been added in the monitoring table.";
$callback->($rsp);
$table->close();
return 1;
}
}
}
my $module_name="xCAT_monitoring::$pname";
#check if the module suppors node status monitoring or not.
if ($::NODESTATMON) {
no strict "refs";
my $snodestatusmon=0;
if (defined(${$module_name."::"}{supportNodeStatusMon})) {
$snodestatusmon=${$module_name."::"}{supportNodeStatusMon}->();
}
if (!$snodestatusmon) {
my $rsp={};
$rsp->{data}->[0]="$pname does not support node status monitoring.";
$callback->($rsp);
$table->close();
return 1;
}
}
#update the monsetting table
if ($settings) {
my $table1=xCAT::Table->new("monsetting", -create => 1,-autocommit => 1);
my %key_col1 = (name=>$pname);
#parse the settings. Setting format: key="value",key="value"....
while ($settings =~ s/^\[([^\[\]\=]*)=([^\[\]]*)\](,)*//) {
$key_col1{key}=$1;
my %setting_hash=();
$setting_hash{value}=$2;
$table1->setAttribs(\%key_col1, \%setting_hash);
}
$table1->close();
}
#update the monitoring table
my %key_col = (name=>$pname);
my $nstat='N';
if ($::NODESTATMON) {
$nstat='Y';
$nodestatmon=1;
}
my %tb_cols=(nodestatmon=>$nstat, disable=>"1");
$table->setAttribs(\%key_col, \%tb_cols);
$table->close();
#updating the postscript table
no strict "refs";
my $postscripts_h={};
if (defined(${$module_name."::"}{getPostscripts})) {
my $postscripts_h=${$module_name."::"}{getPostscripts}->();
my @pn=keys(%$postscripts_h);
if (@pn>0) {
my $table2=xCAT::Table->new("postscripts", -create =>1);
if (!$table2) {
my $rsp={};
$rsp->{data}->[0]="Cannot open the postscripts table.\nFailed to set the postscripts for $pname.";
$callback->($rsp);
return 1;
}
foreach my $group (@pn) {
my $posts=$postscripts_h->{$group};
if ($posts) {
(my $ref) = $table2->getAttribs({node => $group}, 'postscripts');
if ($ref and $ref->{postscripts}) {
my @old_a=split(',', $ref->{postscripts});
my @new_a=split(',', $posts);
my %new_h=();
foreach my $new_tmp (@new_a) {
my $found=0;
foreach my $old_tmp (@old_a) {
if ($old_tmp eq $new_tmp) { $found=1; last; }
}
if (!$found) { $new_h{$new_tmp}=1;}
}
if (keys(%new_h) > 0) {
foreach (keys(%new_h)) { push(@old_a, $_); }
my $new_post=join(',', @old_a);
my %key_col2 = (node=>$group);
my %tb_cols2=(postscripts=>$new_post);
$table2->setAttribs(\%key_col2, \%tb_cols2);
}
} else {
my %key_col2 = (node=>$group);
my %tb_cols2=(postscripts=>$posts);
$table2->setAttribs(\%key_col2, \%tb_cols2);
}
}
}
$table2->close();
}
}
} else {
my $rsp={};
$rsp->{data}->[0]="Failed to open the monitoring table.";
$callback->($rsp);
return 1;
}
return 0;
}
#--------------------------------------------------------------------------------
=head3 monrm
This function removes the given monitoring plug-in from the 'monitoring' table.
It also removed the postscritps for the module from the 'postscritps' table.
Arguments:
request -- a hash table which contains the command name and the arguments.
callback - the pointer to the callback function.
args - The format of the args is:
[-h|--help|-v|--version] or
name
where
name is the monitoring plug-in name. For example: rmcmon.
The specified plug-in will be stopped for monitoring the xCAT
cluster if it is running and then removed from the monitoring table.
Returns:
0 for success.
1 for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub monrm {
my $request = shift;
my $callback = shift;
my $args=$request->{arg};
my $doreq = shift;
if (xCAT::Utils->isServiceNode()) {
my $rsp={};
$rsp->{data}->[0]= "This command is not supported on a service node.";
$callback->($rsp);
return (1, "");
}
# subroutine to display the usage
sub monrm_usage
{
my $cb=shift;
my $rsp={};
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " monrm name";
$rsp->{data}->[2]= " monrm [-h|--help|-v|--version]";
$rsp->{data}->[3]= " name is the name of the monitoring plug-in module registered in the monitoring table.";
$cb->($rsp);
}
@ARGV=();
if ($args) { @ARGV=@{$args};}
# parse the options
if(!GetOptions(
'h|help' => \$::HELP,
'v|version' => \$::VERSION,))
{
&monrm_usage($callback);
return (1, "");
}
# display the usage if -h or --help is specified
if ($::HELP) {
&monrm_usage($callback);
return (1, "");
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my $rsp={};
$rsp->{data}->[0]= xCAT::Utils->Version();;
$callback->($rsp);
return (1, "");
}
my $pname;
if (@ARGV < 1)
{
&monrm_usage($callback);
return (1, "");
}
else {
$pname=$ARGV[0];
}
my $disable=1;
my $found=0;
my $table=xCAT::Table->new("monitoring", -create =>1);
if ($table) {
my $tmp1=$table->getAllEntries();
if (defined($tmp1) && (@$tmp1 > 0)) {
foreach(@$tmp1) {
if ($pname eq $_->{name}) {
if ($_->{disable} =~ /0|NO|No|no|N|n/) { $disable=0; }
$found=1;
}
}
}
if (!$found) {
my $rsp={};
$rsp->{data}->[0]="$pname is not in the monitoring talble.";
$callback->($rsp);
$table->close();
return 0;
}
if (!$disable) {
my $rsp={};
$rsp->{data}->[0]="Please run command 'monstop $pname' to stop monitoring before running this command.";
$callback->($rsp);
$table->close();
return 0;
}
my %key_col = (name=>$pname);
$table->delEntries(\%key_col);
$table->close();
#remove the postscripts for the module from the postscript table
no strict "refs";
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
my $module_name="xCAT_monitoring::$pname";
if (!-e $file_name) {
return 0;
} else {
#load the module in memory
eval {require($file_name)};
if ($@) {
return 0;
}
}
my $postscripts_h={};
if (defined(${$module_name."::"}{getPostscripts})) {
my $postscripts_h=${$module_name."::"}{getPostscripts}->();
my @pn=keys(%$postscripts_h);
if (@pn>0) {
my $table2=xCAT::Table->new("postscripts", -create =>1);
if (!$table2) {
my $rsp={};
$rsp->{data}->[0]="Cannot open the postscripts table.\nFailed to remove the postscripts for $pname.";
$callback->($rsp);
return 1;
}
foreach my $group (@pn) {
my $posts=$postscripts_h->{$group};
if ($posts) {
(my $ref) = $table2->getAttribs({node => $group}, 'postscripts');
if ($ref and $ref->{postscripts}) {
my @old_a=split(',', $ref->{postscripts});
my @new_a=split(',', $posts);
my %new_h=();
my @new_post_a=();
foreach my $old_tmp (@old_a) {
my $found=0;
foreach my $new_tmp (@new_a) {
if ($old_tmp eq $new_tmp) { $found=1; last; }
}
if (!$found) { push(@new_post_a,$old_tmp); }
}
if (@new_post_a > 0) {
my $new_post=join(',', @new_post_a);
if ( $new_post ne $ref->{postscripts} ) {
my %key_col2 = (node=>$group);
my %tb_cols2=(postscripts=>$new_post);
$table2->setAttribs(\%key_col2, \%tb_cols2);
}
} else {
my %key_col2 = (node=>$group);
$table2->delEntries(\%key_col2);
}
}
}
}
$table2->close();
}
}
} else {
my $rsp={};
$rsp->{data}->[0]="Cannot open monitoring table.";
$callback->($rsp);
return 1;
}
return 0;
}
#--------------------------------------------------------------------------------
=head3 preprocess_moncfg
This function handles the syntax checking for moncfg command.
Arguments:
callback - the pointer to the callback function.
args - The format of the args is:
[-h|--help|-v|--version] or
name [noderange] [-r|--remote]
where
name is the monitoring plug-in name. For example: rmcmon.
The specified plug-in will be invoked for configuring the cluster to monitor the nodes.
noderange a range of nodes to be configured for. Default is all.
-r|--remote indicates that both monservers and the nodes need to configured.
The defaults is monservers only.
Returns:
(0, $modulename, $nodestatutmon, $scope, \@nodes) for success. scope is the scope of the
actions. 1 means monervers only, 2 means both nodes and monservers.
(1, "") for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub preprocess_moncfg
{
my $args=shift;
my $callback=shift;
# subroutine to display the usage
sub moncfg_usage
{
my $cb=shift;
my $rsp={};
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " moncfg name [noderange] [-r|--remote]";
$rsp->{data}->[2]= " moncfg [-h|--help|-v|--version]";
$rsp->{data}->[3]= " name is the name of the monitoring plug-in module to be invoked.";
$rsp->{data}->[4]= " Use 'monls -a' command to list all the monitoring plug-in names.";
$rsp->{data}->[5]= " noderange is a range of nodes to be configured for. The default is all nodes.";
$rsp->{data}->[6]= " -r|--remote indicates that both monservers and the nodes need to be configured.\n The default is monservers only.";
$rsp->{data}->[7]= " The default is monservers only.";
$cb->($rsp);
}
@ARGV=();
if ($args) { @ARGV=@{$args};}
# parse the options
if(!GetOptions(
'h|help' => \$::HELP,
'v|version' => \$::VERSION,
'r|remote' => \$::REMOTE,))
{
&moncfg_usage($callback);
return;
}
# display the usage if -h or --help is specified
if ($::HELP) {
&moncfg_usage($callback);
return;
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my $rsp={};
$rsp->{data}->[0]= xCAT::Utils->Version();
$callback->($rsp);
return;
}
my $pname="";
my $scope=0;
my @nodes=();
my $nodestatmon=0;
if ($::REMOTE) { $scope=2;}
if (@ARGV < 1)
{
&moncfg_usage($callback);
return (1, "");
}
else {
$pname=$ARGV[0];
if (@ARGV > 1) {
my $noderange=$ARGV[1];
@nodes = noderange($noderange);
if (nodesmissed) {
my $rsp={};
$rsp->{data}->[0]= "Invalid nodes in noderange:".join(',',nodesmissed);
$callback->($rsp);
return (1, "");
}
}
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
if (!-e $file_name) {
my $rsp={};
$rsp->{data}->[0]="File $file_name does not exist.";
$callback->($rsp);
return (1, "");
} else {
#load the module in memory
eval {require($file_name)};
if ($@) {
my $rsp={};
$rsp->{data}->[0]="The file $file_name has compiling errors:\n$@\n";
$callback->($rsp);
return (1, "");
}
}
}
my $table=xCAT::Table->new("monitoring", -create => 1,-autocommit => 1);
if ($table) {
my $found=0;
my $tmp1=$table->getAllEntries();
if (defined($tmp1) && (@$tmp1 > 0)) {
foreach(@$tmp1) {
if ($pname eq $_->{name}) {
$found=1;
if ($_->{nodestatmon} =~ /1|Yes|yes|YES|Y|y/) { $nodestatmon=1;}
last;
}
}
}
if (!$found) {
my $rsp={};
$rsp->{data}->[0]="$pname cannot be found in the monitoring table.";
$callback->($rsp);
$table->close();
return (1, "");
}
$table->close();
} else {
my $rsp={};
$rsp->{data}->[0]="Failed to open the monitoring table.";
$callback->($rsp);
return (1, "");
}
return (0, $pname, $nodestatmon, $scope, \@nodes);
}
#--------------------------------------------------------------------------------
=head3 moncfg
This function configures the cluster for the given nodes. It includes configuring
and setting up the 3rd party monitoring software for monitoring the given nodes.
Arguments:
request -- a hash table which contains the command name and the arguments.
callback -- the callback pointer for error and status displaying. It can be null.
Returns:
0 for success. The output is returned through the callback pointer.
1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub moncfg
{
my $request=shift;
my $callback=shift;
my $pname=$request->{module}->[0];
my $nodestatmon=$request->{nodestatmon}->[0];
my $scope=$request->{scope}->[0];
my $nodeinfo=$request->{nodeinfo}->[0];
my @nodes=split(',', $nodeinfo);
print "moncfg get called: pname=$pname\nnodestatmon=$nodestatmon\nnodeinfo=@nodes\nscope=$scope\n";
xCAT_monitoring::monitorctrl->config([$pname], \@nodes, $scope, $callback);
return 0;
}
#--------------------------------------------------------------------------------
=head3 preprocess_mondecfg
This function handles the syntax checking for mondecfg command.
Arguments:
callback - the pointer to the callback function.
args - The format of the args is:
[-h|--help|-v|--version] or
name [noderange] [-r|--remote]
where
name is the monitoring plug-in name. For example: rmcmon.
The specified plug-in will be invoked for deconfiguring the cluster to monitor the nodes.
noderange a range of nodes to be deconfigured for. Default is all.
-r|--remote indicates that both monservers and the nodes need to be deconfigured.
The defaults is monservers only.
Returns:
(0, $modulename, $nodestatutmon, $scope, \@nodes) for success. scope is the scope of the
actions. 1 means monervers only, 2 means both nodes and monservers.
(1, "") for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub preprocess_mondecfg
{
my $args=shift;
my $callback=shift;
# subroutine to display the usage
sub mondecfg_usage
{
my $cb=shift;
my $rsp={};
$rsp->{data}->[0]= "Usage:";
$rsp->{data}->[1]= " mondecfg name [noderange] [-r|--remote]";
$rsp->{data}->[2]= " mondecfg [-h|--help|-v|--version]";
$rsp->{data}->[3]= " name is the name of the monitoring plug-in module to be invoked.";
$rsp->{data}->[4]= " Use 'monls -a' command to list all the monitoring plug-in names.";
$rsp->{data}->[5]= " noderange is a range of nodes to be deconfigured for.";
$rsp->{data}->[6]= " The default is all nodes.";
$rsp->{data}->[7]= " -r|--remote indicates that both monservers and the nodes need to be deconfigured.";
$rsp->{data}->[8]= " The default is monservers only.";
$cb->($rsp);
}
@ARGV=();
if ($args) { @ARGV=@{$args} ; }
# parse the options
if(!GetOptions(
'h|help' => \$::HELP,
'v|version' => \$::VERSION,
'r|remote' => \$::REMOTE,))
{
&mondecfg_usage($callback);
return;
}
# display the usage if -h or --help is specified
if ($::HELP) {
&mondecfg_usage($callback);
return;
}
# display the version statement if -v or --verison is specified
if ($::VERSION)
{
my $rsp={};
$rsp->{data}->[0]= xCAT::Utils->Version();
$callback->($rsp);
return;
}
my $pname="";
my $scope=0;
my @nodes=();
my $nodestatmon=0;
if ($::REMOTE) { $scope=2;}
if (@ARGV < 1)
{
&mondecfg_usage($callback);
return (1, "");
}
else {
$pname=$ARGV[0];
if (@ARGV > 1) {
my $noderange=$ARGV[1];
@nodes = noderange($noderange);
if (nodesmissed) {
my $rsp={};
$rsp->{data}->[0]= "Invalid nodes in noderange:".join(',',nodesmissed);
$callback->($rsp);
return (1, "");
}
}
my $file_name="$::XCATROOT/lib/perl/xCAT_monitoring/$pname.pm";
if (!-e $file_name) {
my $rsp={};
$rsp->{data}->[0]="File $file_name does not exist.";
$callback->($rsp);
return (1, "");
} else {
#load the module in memory
eval {require($file_name)};
if ($@) {
my $rsp={};
$rsp->{data}->[0]="The file $file_name has compiling errors:\n$@\n";
$callback->($rsp);
return (1, "");
}
}
}
my $table=xCAT::Table->new("monitoring", -create => 1,-autocommit => 1);
if ($table) {
my $found=0;
my $tmp1=$table->getAllEntries();
if (defined($tmp1) && (@$tmp1 > 0)) {
foreach(@$tmp1) {
if ($pname eq $_->{name}) {
$found=1;
if ($_->{nodestatmon} =~ /1|Yes|yes|YES|Y|y/) { $nodestatmon=1;}
last;
}
}
}
if (!$found) {
my $rsp={};
$rsp->{data}->[0]="$pname cannot be found in the monitoring table.";
$callback->($rsp);
$table->close();
return (1, "");
}
$table->close();
} else {
my $rsp={};
$rsp->{data}->[0]="Failed to open the monitoring table.";
$callback->($rsp);
return (1, "");
}
return (0, $pname, $nodestatmon, $scope, \@nodes);
}
#--------------------------------------------------------------------------------
=head3 mondecfg
This function deconfigures the cluster for the given nodes. It includes deconfiguring
and clearning up the 3rd party monitoring software for monitoring the given nodes.
Arguments:
names -- a pointer to an array of monitoring plug-in names. If non is specified,
all the plug-ins registered in the monitoring table will be notified.
p_nodes -- a pointer to an arrays of nodes to be removed from the monitoring domain.
none means all.
scope -- the action scope, it indicates the node type the action will take place.
0 means localhost only.
1 means monserver only,
2 means both monservers and nodes,
callback -- the callback pointer for error and status displaying. It can be null.
Returns:
0 for success. The output is returned through the callback pointer.
1. for unsuccess. The error messages are returns through the callback pointer.
=cut
#--------------------------------------------------------------------------------
sub mondecfg
{
my $request=shift;
my $callback=shift;
my $pname=$request->{module}->[0];
my $nodestatmon=$request->{nodestatmon}->[0];
my $scope=$request->{scope}->[0];
my $nodeinfo=$request->{nodeinfo}->[0];
my @nodes=split(',', $nodeinfo);
print "mondecfg get called: pname=$pname\nnodestatmon=$nodestatmon\nnodeinfo=@nodes\nscope=$scope\n";
xCAT_monitoring::monitorctrl->deconfig([$pname], \@nodes, $scope, $callback);
return 0;
}