mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-05 12:37:54 +00:00
d5f882291d
The manual page and the usage message of nodestat give the option -f|--usefping. The preprocessor of the request knows no option f, and the handler of the request spells the long name useping, so --usefping does nothing. An administrator who follows the manual page gets the nmap path, and gets no message that says why. The two places also read different specifications, so an option that one place accepts can reach the other place and take a different meaning. Put the specification in one routine, and let both places read that routine. Give the name usefping to the option, and keep useping as a second name. That spelling has worked since 2.14.2, so a site can have it in a script. The long name of the fping option starts with the same letters as usemon, so --use and --us become names that Getopt::Long cannot decide. Those two abbreviations select usemon today. Keep them with usemon, or an administrator who monitors with them loses the monitoring and gets no message. The change has two other effects. The abbreviations --use and --us no longer select fping as well, which they did only because the two places read different specifications. The bundles -mf and -fm now select both options, which they did not do before. Recovered from the lenovobuild branch.
1345 lines
49 KiB
Perl
1345 lines
49 KiB
Perl
package xCAT_plugin::nodestat;
|
|
|
|
BEGIN
|
|
{
|
|
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
|
}
|
|
use lib "$::XCATROOT/lib/perl";
|
|
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
|
|
|
|
use Socket;
|
|
my $inet6support = eval {
|
|
require Socket6;
|
|
require IO::Socket::INET6;
|
|
1;
|
|
};
|
|
use IO::Handle;
|
|
use Getopt::Long;
|
|
use Data::Dumper;
|
|
use xCAT::GlobalDef;
|
|
use xCAT::NetworkUtils;
|
|
require xCAT::Utils;
|
|
require xCAT::TableUtils;
|
|
require xCAT::ServiceNodeUtils;
|
|
|
|
my %nodesetstats;
|
|
my %chainhash;
|
|
my %default_ports = (
|
|
'ftp' => '21',
|
|
'ssh' => '22',
|
|
'sshd' => '22',
|
|
'pbs' => '15002',
|
|
'pbs_mom' => '15002',
|
|
'xend' => '8002',
|
|
'll' => '9616',
|
|
'loadl' => '9616',
|
|
'loadl_master' => '9616',
|
|
'loadleveler' => '9616',
|
|
'gpfs' => '1191',
|
|
'rdp' => '3389',
|
|
'msrpc' => '135',
|
|
);
|
|
|
|
sub handled_commands {
|
|
return {
|
|
nodestat => 'nodestat',
|
|
nodestat_internal => 'nodestat',
|
|
};
|
|
}
|
|
|
|
sub pinghost {
|
|
my $node = shift;
|
|
my $rc = system("ping -q -n -c 1 -w 1 $node > /dev/null");
|
|
if ($rc == 0) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
sub nodesockopen {
|
|
my $node = shift;
|
|
my $port = shift;
|
|
my $socket;
|
|
my $addr = gethostbyname($node);
|
|
my $sin = sockaddr_in($port, $addr);
|
|
my $proto = getprotobyname('tcp');
|
|
socket($socket, PF_INET, SOCK_STREAM, $proto) || return 0;
|
|
connect($socket, $sin) || return 0;
|
|
return 1;
|
|
}
|
|
|
|
sub installer_query {
|
|
my $node = shift;
|
|
my $destport = 3001;
|
|
my $socket;
|
|
my $text = "";
|
|
if ($inet6support) {
|
|
$socket = IO::Socket::INET6->new(PeerAddr => $node, PeerPort => 3001);
|
|
unless ($socket) { return 0; }
|
|
} else {
|
|
my $proto = getprotobyname('tcp');
|
|
socket($socket, PF_INET, SOCK_STREAM, $proto) || return 0;
|
|
my $addr = gethostbyname($node);
|
|
my $sin = sockaddr_in($destport, $addr);
|
|
connect($socket, $sin) || return 0;
|
|
}
|
|
print $socket "stat \n";
|
|
$socket->flush;
|
|
while (<$socket>) {
|
|
$text .= $_;
|
|
}
|
|
$text =~ s/\n.*//;
|
|
return $text;
|
|
close($socket);
|
|
}
|
|
|
|
|
|
sub getstat {
|
|
my $response = shift;
|
|
foreach (@{ $response->{node} }) {
|
|
$nodesetstats{ $_->{name}->[0] } = $_->{data}->[0];
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 preprocess_request
|
|
|
|
Check and setup for hierarchy
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
sub option_spec {
|
|
return (
|
|
'm|usemon|use|us', 'q|quiet', 'u|updatedb', 'p|powerstat',
|
|
'f|usefping|useping', 'h|help', 'v|version',
|
|
);
|
|
}
|
|
|
|
sub preprocess_request
|
|
{
|
|
my $req = shift;
|
|
my $cb = shift;
|
|
my %sn;
|
|
if (defined $req->{_xcatpreprocessed}->[0] && $req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
|
|
|
|
#exit if preprocessed
|
|
|
|
my $command = $req->{command}->[0];
|
|
if ($command eq "nodestat") {
|
|
|
|
@ARGV = ();
|
|
my $args = $req->{arg};
|
|
if ($args) {
|
|
@ARGV = @{$args};
|
|
}
|
|
|
|
# parse the options
|
|
#Getopt::Long::Configure("posix_default");
|
|
#Getopt::Long::Configure("no_gnu_compat");
|
|
Getopt::Long::Configure("bundling");
|
|
$Getopt::Long::ignorecase = 0;
|
|
my %opt;
|
|
if (!GetOptions(\%opt, option_spec()))
|
|
{
|
|
&usage($cb,1);
|
|
return (1);
|
|
}
|
|
$::MON = $opt{m} ? 1 : 0;
|
|
$::QUIET = $opt{q} ? 1 : 0; #this is a internal flag used by monitoring
|
|
$::UPDATE = $opt{u} ? 1 : 0;
|
|
$::POWER = $opt{p} ? 1 : 0;
|
|
$::USEFPING = $opt{f} ? 1 : 0;
|
|
$::HELP = $opt{h};
|
|
$::VERSION = $opt{v};
|
|
if ($::HELP) {
|
|
&usage($cb);
|
|
return (0);
|
|
}
|
|
if ($::VERSION) {
|
|
my $version = xCAT::Utils->Version();
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "$version";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
return (0);
|
|
}
|
|
my $nodes = $req->{node};
|
|
if (!$nodes)
|
|
{
|
|
&usage($cb,1);
|
|
return (1);
|
|
}
|
|
|
|
$req->{'update'}->[0] = $::UPDATE;
|
|
$req->{'quiet'}->[0] = $::QUIET;
|
|
$req->{'mon'}->[0] = $::MON;
|
|
$req->{'power'}->[0] = $::POWER;
|
|
return [$req];
|
|
}
|
|
|
|
#the following is for nodestat_internal command
|
|
my $nodes = $req->{node};
|
|
my $service = "xcat";
|
|
my @requests;
|
|
if ($nodes) {
|
|
my $usenmapfrommn = 0;
|
|
if (-x '/usr/bin/nmap' or -x '/usr/local/bin/nmap') {
|
|
|
|
#my $sitetab = xCAT::Table->new('site');
|
|
#if ($sitetab) {
|
|
#(my $ref) = $sitetab->getAttribs({key => 'useNmapfromMN'}, 'value');
|
|
my @entries = xCAT::TableUtils->get_site_attribute("useNmapfromMN");
|
|
my $t_entry = $entries[0];
|
|
if (defined($t_entry)) {
|
|
if ($t_entry =~ /1|yes|YES|Y|y/) { $usenmapfrommn = 1; }
|
|
}
|
|
|
|
#}
|
|
}
|
|
|
|
#get monsettings
|
|
my %apps = ();
|
|
my $mon = $req->{'mon'}->[0];
|
|
if ($mon == 1) { %apps = getStatusMonsettings(); }
|
|
|
|
#if no apps specified in the monsetting table, add sshd, pbs and xend
|
|
if (keys(%apps) == 0) {
|
|
$apps{'sshd'}->{'group'} = "ALL"; #ALL means anything on the nodelist table, it is different from all
|
|
$apps{'sshd'}->{'port'} = "22";
|
|
$apps{'https'}->{'group'} = "ALL"; #ALL means anything on the nodelist table, it is different from all
|
|
$apps{'https'}->{'port'} = "443";
|
|
$apps{'pbs'}->{'group'} = "ALL";
|
|
$apps{'pbs'}->{'port'} = "15002";
|
|
$apps{'xend'}->{'group'} = "ALL";
|
|
$apps{'xend'}->{'port'} = "8002";
|
|
$apps{'rdp'}->{'group'} = "ALL";
|
|
$apps{'rdp'}->{'port'} = "3389";
|
|
$apps{'msrpc'}->{'group'} = "ALL";
|
|
$apps{'msrpc'}->{'port'} = "135";
|
|
$apps{'APPS'} = [ 'sshd', 'https', 'pbs', 'xend' ];
|
|
} else {
|
|
|
|
#go thorugh the settings and put defaults in
|
|
foreach my $app (keys(%apps)) {
|
|
if ($app eq 'APPS') { next; }
|
|
if (!exists($apps{$app}->{'group'})) { $apps{$app}->{'group'} = "ALL"; }
|
|
if (exists($apps{$app}->{'cmd'}) || exists($apps{$app}->{'dcmd'}) || exists($apps{$app}->{'lcmd'})) { next; }
|
|
if (exists($apps{$app}->{'port'})) { next; }
|
|
|
|
#add port number in if nothing is specified
|
|
if (exists($default_ports{$app})) { $apps{$app}->{'port'} = $default_ports{$app}; }
|
|
else {
|
|
my $p = `grep "^$app" /etc/services`;
|
|
if ($? == 0) {
|
|
my @a_list = sort(split('\n', $p));
|
|
my @a_temp = split('/', $a_list[0]);
|
|
my @a = split(' ', $a_temp[0]);
|
|
$apps{$app}->{'port'} = $a[1];
|
|
} else {
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Cannot find port number for application $app. Please either specify a port number or a command in monsetting table for $app.";
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
return (0);
|
|
}
|
|
}
|
|
}
|
|
|
|
#always add sshd
|
|
if (!exists($apps{'ssh'}) || !exists($apps{'sshd'})) {
|
|
$apps{'sshd'}->{'group'} = "ALL";
|
|
$apps{'sshd'}->{'port'} = "22";
|
|
my $pa = $apps{'APPS'};
|
|
push @$pa, 'sshd';
|
|
}
|
|
}
|
|
|
|
#print Dumper(%apps);
|
|
# find service nodes for requested nodes
|
|
# build an individual request for each service node
|
|
my $sn = xCAT::ServiceNodeUtils->get_ServiceNode($nodes, $service, "MN");
|
|
|
|
#get the member for each group
|
|
my %groups = ();
|
|
foreach my $app (keys %apps) {
|
|
if ($app eq 'APPS') { next; }
|
|
my $group = $apps{$app}->{'group'};
|
|
if (($group) && ($group ne "ALL") && (!exists($groups{$group}))) {
|
|
my @tmp_nodes = xCAT::NodeRange::noderange($group);
|
|
foreach (@tmp_nodes) {
|
|
$groups{$group}->{$_} = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
# build each request for each service node
|
|
my $all_apps = $apps{'APPS'};
|
|
my %all_porthash = (); #stores all the port apps if usenmapfrommn=1
|
|
my %lcmdhash = (); #('myapp2,myapp3'=> {
|
|
# lcmd=>'/tmp/mycmd1,/usr/bin/date',
|
|
# node=>[node1,node2]
|
|
# }
|
|
#)
|
|
foreach my $snkey (keys %$sn)
|
|
{
|
|
my $reqcopy = {%$req};
|
|
$reqcopy->{node} = $sn->{$snkey};
|
|
$reqcopy->{'_xcatdest'} = $snkey;
|
|
$reqcopy->{_xcatpreprocessed}->[0] = 1;
|
|
|
|
$reqcopy->{'useNmapfromMN'}->[0] = $usenmapfrommn;
|
|
$reqcopy->{'allapps'} = $all_apps;
|
|
|
|
my %porthash = (); #('sshd,ll'=> {
|
|
# port=>'22,5001',
|
|
# node=>[node1,node2]
|
|
# }
|
|
#)
|
|
my %cmdhash = (); #('gpfs,myapp'=> {
|
|
# cmd=>'/tmp/mycmd1,/usr/bin/date',
|
|
# node=>[node1,node2]
|
|
# }
|
|
#)
|
|
my %dcmdhash = (); #('myapp2,myapp3'=> {
|
|
# dcmd=>'/tmp/mycmd1,/usr/bin/date',
|
|
# node=>[node1,node2]
|
|
# }
|
|
#)
|
|
my @nodes_for_sn = @{ $sn->{$snkey} };
|
|
|
|
foreach my $node (@nodes_for_sn) {
|
|
my @ports;
|
|
my @portapps;
|
|
my @cmds;
|
|
my @cmdapps;
|
|
my @dcmds;
|
|
my @dcmdapps;
|
|
my @lcmdapps;
|
|
my @lcmds;
|
|
|
|
foreach my $app (keys %apps) {
|
|
if ($app eq 'APPS') { next; }
|
|
my $group = $apps{$app}->{'group'};
|
|
if (($group eq "ALL") || ($groups{$group}->{$node})) {
|
|
|
|
#print "app=$app\n";
|
|
if (exists($apps{$app}->{'port'})) {
|
|
push @ports, $apps{$app}->{'port'};
|
|
push @portapps, $app;
|
|
}
|
|
elsif (exists($apps{$app}->{'cmd'})) {
|
|
push @cmds, $apps{$app}->{'cmd'};
|
|
push @cmdapps, $app;
|
|
}
|
|
elsif (exists($apps{$app}->{'dcmd'})) {
|
|
push @dcmds, $apps{$app}->{'dcmd'};
|
|
push @dcmdapps, $app;
|
|
}
|
|
elsif (exists($apps{$app}->{'lcmd'})) {
|
|
push @lcmds, $apps{$app}->{'lcmd'};
|
|
push @lcmdapps, $app;
|
|
}
|
|
}
|
|
}
|
|
|
|
#print "ports=@ports\n";
|
|
#print "portapps=@portapps\n";
|
|
#print "cmds=@cmds\n";
|
|
#print "cmdapps=@cmdapps\n";
|
|
#print "dcmds=@dcmds\n";
|
|
#print "dcmdapps=@dcmdapps\n";
|
|
if (@portapps > 0) {
|
|
my $tmpapps = join(',', @portapps);
|
|
if (($usenmapfrommn == 1) && (@cmdapps == 0) && (@dcmdapps == 0) && (@lcmdapps == 0)) {
|
|
|
|
#this is the case where mn handles ports for all nodes using nmap
|
|
#The current limitation is that when there are cmd or dcmd specified for the node
|
|
# nmap has to be done on the service node because if both mn and sn update the appstatus
|
|
# one will overwites the other.
|
|
if (exists($all_porthash{$tmpapps})) {
|
|
my $pa = $all_porthash{$tmpapps}->{'node'};
|
|
push @$pa, $node;
|
|
} else {
|
|
$all_porthash{$tmpapps}->{'node'} = [$node];
|
|
$all_porthash{$tmpapps}->{'port'} = join(',', @ports);
|
|
}
|
|
} else {
|
|
if (exists($porthash{$tmpapps})) {
|
|
my $pa = $porthash{$tmpapps}->{'node'};
|
|
push @$pa, $node;
|
|
} else {
|
|
$porthash{$tmpapps}->{'node'} = [$node];
|
|
$porthash{$tmpapps}->{'port'} = join(',', @ports);
|
|
}
|
|
}
|
|
}
|
|
if (@cmdapps > 0) {
|
|
my $tmpapps = join(',', @cmdapps);
|
|
if (exists($cmdhash{$tmpapps})) {
|
|
my $pa = $cmdhash{$tmpapps}->{'node'};
|
|
push @$pa, $node;
|
|
} else {
|
|
$cmdhash{$tmpapps}->{'node'} = [$node];
|
|
$cmdhash{$tmpapps}->{'cmd'} = join(',', @cmds);
|
|
}
|
|
}
|
|
if (@dcmdapps > 0) {
|
|
my $tmpapps = join(',', @dcmdapps);
|
|
if (exists($dcmdhash{$tmpapps})) {
|
|
my $pa = $dcmdhash{$tmpapps}->{'node'};
|
|
push @$pa, $node;
|
|
} else {
|
|
$dcmdhash{$tmpapps}->{'node'} = [$node];
|
|
$dcmdhash{$tmpapps}->{'dcmd'} = join(',', @dcmds);
|
|
}
|
|
}
|
|
if (@lcmdapps > 0) {
|
|
my $i = 0;
|
|
foreach my $lapp (@lcmdapps) {
|
|
if (exists($lcmdhash{$lapp})) {
|
|
my $pa = $lcmdhash{$lapp}->{'node'};
|
|
push @$pa, $node;
|
|
} else {
|
|
$lcmdhash{$lapp}->{'node'} = [$node];
|
|
$lcmdhash{$lapp}->{'lcmd'} = $lcmds[$i];
|
|
}
|
|
$i++;
|
|
}
|
|
}
|
|
} #end foreach (@nodes_for_sn)
|
|
|
|
#print Dumper(%porthash);
|
|
#print "cmdhash=" . Dumper(%cmdhash);
|
|
#now push the settings into the requests
|
|
my $i = 1;
|
|
if ((keys(%porthash) == 0) && (keys(%cmdhash) == 0) && (keys(%dcmdhash) == 0) && (keys(%lcmdhash) == 0)) { next; }
|
|
foreach my $tmpapps (keys %porthash) {
|
|
$reqcopy->{'portapps'}->[0] = scalar keys %porthash;
|
|
$reqcopy->{"portapps$i"}->[0] = $tmpapps;
|
|
$reqcopy->{ "portapps$i" . "port" }->[0] = $porthash{$tmpapps}->{'port'};
|
|
$reqcopy->{ "portapps$i" . "node" } = $porthash{$tmpapps}->{'node'};
|
|
$i++;
|
|
}
|
|
$i = 1;
|
|
foreach my $tmpapps (keys %cmdhash) {
|
|
$reqcopy->{'cmdapps'}->[0] = scalar keys %cmdhash;
|
|
$reqcopy->{"cmdapps$i"}->[0] = $tmpapps;
|
|
$reqcopy->{ "cmdapps$i" . "cmd" }->[0] = $cmdhash{$tmpapps}->{'cmd'};
|
|
$reqcopy->{ "cmdapps$i" . "node" } = $cmdhash{$tmpapps}->{'node'};
|
|
$i++;
|
|
}
|
|
$i = 1;
|
|
foreach my $tmpapps (keys %dcmdhash) {
|
|
$reqcopy->{'dcmdapps'}->[0] = scalar keys %dcmdhash;
|
|
$reqcopy->{"dcmdapps$i"}->[0] = $tmpapps;
|
|
$reqcopy->{ "dcmdapps$i" . "dcmd" }->[0] = $dcmdhash{$tmpapps}->{'dcmd'};
|
|
$reqcopy->{ "dcmdapps$i" . "node" } = $dcmdhash{$tmpapps}->{'node'};
|
|
$i++;
|
|
}
|
|
|
|
|
|
#done
|
|
push @requests, $reqcopy;
|
|
} #enf sn_key
|
|
|
|
|
|
#print "apps=" . Dumper(%apps);
|
|
|
|
#mn handles all nmap when useNmapfromMN=1 on the site table
|
|
if (($usenmapfrommn == 1) && (keys(%all_porthash) > 0)) {
|
|
my @hostinfo = xCAT::NetworkUtils->determinehostname();
|
|
my %iphash = ();
|
|
foreach (@hostinfo) { $iphash{$_} = 1; }
|
|
my $handled = 0;
|
|
foreach my $req (@requests) {
|
|
my $currsn = $req->{'_xcatdest'};
|
|
if (exists($iphash{$currsn})) {
|
|
my $i = 1;
|
|
foreach my $tmpapps (keys %all_porthash) {
|
|
$req->{'portapps'}->[0] = scalar keys %all_porthash;
|
|
$req->{"portapps$i"}->[0] = $tmpapps;
|
|
$req->{ "portapps$i" . "port" }->[0] = $all_porthash{$tmpapps}->{'port'};
|
|
$req->{ "portapps$i" . "node" } = $all_porthash{$tmpapps}->{'node'};
|
|
$i++;
|
|
}
|
|
$handled = 1;
|
|
last;
|
|
}
|
|
}
|
|
|
|
if (!$handled) {
|
|
my $reqcopy = {%$req};
|
|
$reqcopy->{_xcatpreprocessed}->[0] = 1;
|
|
$reqcopy->{'useNmapfromMN'}->[0] = $usenmapfrommn;
|
|
$reqcopy->{'allapps'} = $all_apps;
|
|
my $i = 1;
|
|
foreach my $tmpapps (keys %all_porthash) {
|
|
$reqcopy->{'portapps'}->[0] = scalar keys %all_porthash;
|
|
$reqcopy->{"portapps$i"}->[0] = $tmpapps;
|
|
$reqcopy->{ "portapps$i" . "port" }->[0] = $all_porthash{$tmpapps}->{'port'};
|
|
$reqcopy->{ "portapps$i" . "node" } = $all_porthash{$tmpapps}->{'node'};
|
|
$i++;
|
|
}
|
|
push @requests, $reqcopy;
|
|
}
|
|
}
|
|
|
|
|
|
#if ($usenmapfrommn) {
|
|
# my $reqcopy = {%$req};
|
|
# $reqcopy->{'update'}->[0]=$::UPDATE;
|
|
# $reqcopy->{'useNmapfromMN'}->[0]=1;
|
|
# if (!$::UPDATE) {
|
|
# push @requests, $reqcopy;
|
|
# return \@requests; #do not distribute, nodestat seems to lose accuracy and slow down distributed, if using nmap
|
|
# }
|
|
#}
|
|
|
|
#now handle local commands
|
|
#print "lcmdhash=" . Dumper(%lcmdhash);
|
|
if (keys(%lcmdhash) > 0) {
|
|
my @hostinfo = xCAT::NetworkUtils->determinehostname();
|
|
my %iphash = ();
|
|
foreach (@hostinfo) { $iphash{$_} = 1; }
|
|
my $handled = 0;
|
|
foreach my $req (@requests) {
|
|
my $currsn = $req->{'_xcatdest'};
|
|
if (exists($iphash{$currsn})) {
|
|
my $i = 1;
|
|
foreach my $lapp (keys %lcmdhash) {
|
|
$req->{'lcmdapps'}->[0] = scalar keys %lcmdhash;
|
|
$req->{"lcmdapps$i"}->[0] = $lapp;
|
|
$req->{ "lcmdapps$i" . "cmd" }->[0] = $lcmdhash{$lapp}->{'lcmd'};
|
|
$req->{ "lcmdapps$i" . "node" } = $lcmdhash{$lapp}->{'node'};
|
|
$i++;
|
|
}
|
|
$handled = 1;
|
|
last;
|
|
}
|
|
}
|
|
|
|
if (!$handled) {
|
|
my $reqcopy = {%$req};
|
|
$reqcopy->{_xcatpreprocessed}->[0] = 1;
|
|
$reqcopy->{'allapps'} = $all_apps;
|
|
my $i = 1;
|
|
foreach my $lapp (keys %lcmdhash) {
|
|
$reqcopy->{'lcmdapps'}->[0] = scalar keys %lcmdhash;
|
|
$reqcopy->{"lcmdapps$i"}->[0] = $lapp;
|
|
$reqcopy->{ "lcmdapps$i" . "cmd" }->[0] = $lcmdhash{$lapp}->{'lcmd'};
|
|
$reqcopy->{ "lcmdapps$i" . "node" } = $lcmdhash{$lapp}->{'node'};
|
|
$i++;
|
|
}
|
|
push @requests, $reqcopy;
|
|
}
|
|
}
|
|
}
|
|
|
|
return \@requests;
|
|
}
|
|
|
|
sub interrogate_node { #Meant to run against confirmed up nodes
|
|
my $node = shift;
|
|
my $doreq = shift;
|
|
my $p_tmp = shift;
|
|
my %portservices = %$p_tmp;
|
|
|
|
my $status = "";
|
|
my $appsd = ""; #detailed status
|
|
my $ret = {};
|
|
$ret->{'status'} = "ping";
|
|
|
|
foreach my $port (keys(%portservices)) {
|
|
if (nodesockopen($node, $port)) {
|
|
$status .= $portservices{$port} . ",";
|
|
$appsd .= $portservices{$port} . "=up,";
|
|
} else {
|
|
$appsd .= $portservices{$port} . "=down,";
|
|
}
|
|
}
|
|
|
|
$status =~ s/,$//;
|
|
$appsd =~ s/,$//;
|
|
$ret->{'appsd'} = $appsd;
|
|
if ($status) {
|
|
$ret->{'appstatus'} = $status;
|
|
return $ret;
|
|
}
|
|
if ($status = installer_query($node)) {
|
|
$ret->{'status'} = $status;
|
|
return $ret;
|
|
} else { #pingable, but no *clue* as to what the state may be
|
|
$doreq->({ command => ['nodeset'],
|
|
node => [$node],
|
|
arg => ['stat'] },
|
|
\&getstat);
|
|
$ret->{'status'} = 'ping ' . $nodesetstats{$node};
|
|
return $ret;
|
|
}
|
|
}
|
|
|
|
sub process_request_nmap {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $doreq = shift;
|
|
my $nodelist = shift;
|
|
my $p_tmp = shift;
|
|
my %portservices = %$p_tmp;
|
|
my @nodes = ();
|
|
if ($nodelist) { @nodes = @$nodelist; }
|
|
|
|
my %nodebyip;
|
|
my @livenodes;
|
|
my %unknownnodes;
|
|
my $chaintab = xCAT::Table->new('chain', -create => 0);
|
|
if ($chaintab) {
|
|
%chainhash = %{ $chaintab->getNodesAttribs(\@nodes, ['currstate']) };
|
|
}
|
|
my $hoststab = xCAT::Table->new('hosts', -create => 0);
|
|
my %hostsents;
|
|
if ($hoststab) { %hostsents = %{ $hoststab->getNodesAttribs(\@nodes, ['ip']) }; }
|
|
my @ips;
|
|
my @ip6s;
|
|
foreach (@nodes) {
|
|
$unknownnodes{$_} = 1;
|
|
my $ip = undef;
|
|
if (($hostsents{$_}) && ($hostsents{$_}->[0]->{ip})) {
|
|
$ip = $hostsents{$_}->[0]->{ip};
|
|
$nodebyip{$ip} = $_;
|
|
$ip = xCAT::NetworkUtils->getipaddr($ip);
|
|
$nodebyip{$ip} = $_;
|
|
} else {
|
|
$ip = xCAT::NetworkUtils->getipaddr($_);
|
|
}
|
|
if (!defined $ip) {
|
|
my %rsp;
|
|
$rsp{name} = [$_];
|
|
$rsp{data} = ["Please make sure $_ exists in /etc/hosts or DNS or hosts table"];
|
|
$callback->({ node => [ \%rsp ] });
|
|
} else {
|
|
if ($ip =~ /:/) {
|
|
push @ip6s, $ip;
|
|
} else {
|
|
push @ips, $ip;
|
|
}
|
|
$nodebyip{$ip} = $_;
|
|
}
|
|
}
|
|
|
|
my $ret = {};
|
|
my $node;
|
|
my $fping;
|
|
my $ports = join ',', keys %portservices;
|
|
my %deadnodes;
|
|
foreach (@nodes) {
|
|
$deadnodes{$_} = 1;
|
|
}
|
|
|
|
#print "nmap -PE --send-ip -p $ports,3001 ".join(' ',@nodes) . "\n";
|
|
# open($fping,"nmap -PE --send-ip -p $ports,3001 ".join(' ',@nodes). " 2> /dev/null|") or die("Can't start nmap: $!");
|
|
my $currnode = '';
|
|
my $port;
|
|
my $state;
|
|
my %states;
|
|
my %rsp;
|
|
my $installquerypossible = 0;
|
|
my @nodesetnodes = ();
|
|
|
|
# get additional options from site table
|
|
my @nmap_options = xCAT::TableUtils->get_site_attribute("nmapoptions");
|
|
my $more_options = "";
|
|
if (defined($nmap_options[0])) {
|
|
$more_options = $nmap_options[0];
|
|
}
|
|
|
|
foreach my $ip6 (0, 1) { #first pass, ipv4, second pass ipv6
|
|
if ($ip6 and scalar(@ip6s)) {
|
|
open($fping, "nmap --unprivileged -6 -PS$ports,3001 -n --send-ip -p $ports,3001 $more_options " . join(' ', @ip6s) . " 2> /dev/null|") or die("Can't start nmap: $!");
|
|
} elsif (not $ip6 and scalar(@ips)) {
|
|
open($fping, "nmap --unprivileged -PA80,443,22 -PE -n --send-ip -p $ports,3001 $more_options " . join(' ', @ips) . " 2> /dev/null|") or die("Can't start nmap: $!");
|
|
} else { next; }
|
|
while (<$fping>) {
|
|
if (/Interesting ports on ([^ ]*)[: ]/ or /Nmap scan report for ([^ ]*)/) {
|
|
my $tmpnode = $1;
|
|
if ($currnode) { #if still thinking about last node, flush him out
|
|
my $status = join ',', sort keys %states;
|
|
my $appsd = "";
|
|
foreach my $portnum (keys %portservices) {
|
|
my $app_t = $portservices{$portnum};
|
|
if ($states{$app_t}) { $appsd .= $app_t . "=up,"; }
|
|
else { $appsd .= $app_t . "=down,"; }
|
|
}
|
|
$appsd =~ s/,$//;
|
|
my $target = $currnode;
|
|
if ($hostsents{$target} and $hostsents{$target}->[0]->{ip}) { $target = $hostsents{$target}->[0]->{ip}; }
|
|
|
|
if ($status or ($installquerypossible and $status = installer_query($target))) { #pingable, but no *clue* as to what the state may be
|
|
$ret->{$currnode}->{'status'} = "ping";
|
|
$ret->{$currnode}->{'appstatus'} = $status;
|
|
$ret->{$currnode}->{'appsd'} = $appsd;
|
|
$currnode = "";
|
|
%states = ();
|
|
} else {
|
|
push @nodesetnodes, $currnode; #Aggregate call to nodeset
|
|
}
|
|
}
|
|
$currnode = $tmpnode;
|
|
$currnode =~ s/:$//;
|
|
$currnode =~ s/\n$//;
|
|
|
|
|
|
my $nip;
|
|
if ($nip = xCAT::NetworkUtils->getipaddr($currnode)) { #reverse lookup may not resemble the nodename, key by ip
|
|
if ($nodebyip{$nip}) {
|
|
$currnode = $nodebyip{$nip};
|
|
}
|
|
}
|
|
$installquerypossible = 0; #reset possibility indicator
|
|
%rsp = ();
|
|
unless ($deadnodes{$currnode}) {
|
|
my $shortname;
|
|
foreach (keys %deadnodes) {
|
|
if (/\./) {
|
|
$shortname = $_;
|
|
$shortname =~ s/\..*//;
|
|
}
|
|
if ($currnode =~ /^$_\./ or ($shortname and $shortname eq $currnode)) {
|
|
$currnode = $_;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
delete $deadnodes{$currnode};
|
|
} elsif ($currnode) {
|
|
|
|
#if (/^MAC/) { #oops not all nmap records end with MAC
|
|
if (/^PORT/) { next; }
|
|
($port, $state) = split;
|
|
if ($port and $port =~ /^(\d*)\// and $state eq 'open') {
|
|
if ($1 eq "3001" and defined($chainhash{$currnode}->[0]->{currstate}) and $chainhash{$currnode}->[0]->{currstate} =~ /^install/) {
|
|
$installquerypossible = 1; #It is possible to actually query node
|
|
} elsif ($1 ne "3001") {
|
|
$states{ $portservices{$1} } = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($currnode) {
|
|
my $status = join ',', sort keys %states;
|
|
my $appsd = "";
|
|
foreach my $portnum (keys %portservices) {
|
|
my $app_t = $portservices{$portnum};
|
|
if ($states{$app_t}) { $appsd .= $app_t . "=up,"; }
|
|
else { $appsd .= $app_t . "=down,"; }
|
|
}
|
|
$appsd =~ s/,$//;
|
|
|
|
my $target = $currnode;
|
|
if ($hostsents{$target} and $hostsents{$target}->[0]->{ip}) { $target = $hostsents{$target}->[0]->{ip}; }
|
|
if ($status or ($installquerypossible and $status = installer_query($target))) { #pingable, but no *clue* as to what the state may be
|
|
$ret->{$currnode}->{'status'} = "ping";
|
|
$ret->{$currnode}->{'appstatus'} = $status;
|
|
$ret->{$currnode}->{'appsd'} = $appsd;
|
|
$currnode = "";
|
|
%states = ();
|
|
} else {
|
|
push @nodesetnodes, $currnode; #Aggregate call to nodeset
|
|
}
|
|
}
|
|
|
|
if (@nodesetnodes) {
|
|
$doreq->({ command => ['nodeset'],
|
|
node => \@nodesetnodes,
|
|
arg => ['stat'] },
|
|
\&getstat);
|
|
foreach (@nodesetnodes) {
|
|
$ret->{$_}->{'status'} = $nodesetstats{$_};
|
|
}
|
|
}
|
|
foreach $currnode (sort keys %deadnodes) {
|
|
$ret->{$currnode}->{'status'} = "noping";
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
|
|
sub process_request_port {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $doreq = shift;
|
|
my $nodelist = shift;
|
|
my $p_tmp = shift;
|
|
my %portservices = %$p_tmp;
|
|
my @nodes = ();
|
|
if ($nodelist) { @nodes = @$nodelist; }
|
|
|
|
my %unknownnodes;
|
|
foreach (@nodes) {
|
|
$unknownnodes{$_} = 1;
|
|
my $packed_ip = undef;
|
|
$packed_ip = xCAT::NetworkUtils->getipaddr($_);
|
|
if (!defined $packed_ip) {
|
|
my %rsp;
|
|
$rsp{name} = [$_];
|
|
$rsp{data} = ["Please make sure $_ exists in /etc/hosts"];
|
|
$callback->({ node => [ \%rsp ] });
|
|
}
|
|
}
|
|
|
|
my $status = {};
|
|
|
|
if (@nodes > 0) {
|
|
my $node;
|
|
my $fping;
|
|
my $fpingcmd;
|
|
for my $fp (qw(/usr/sbin/fping /usr/bin/fping /sbin/fping /bin/fping /usr/local/sbin/fping /usr/local/bin/fping)) {
|
|
if (-x $fp) { $fpingcmd = $fp; last; }
|
|
}
|
|
unless ($fpingcmd) {
|
|
my $rsp = {};
|
|
$rsp->{error}->[0] =
|
|
"Unable to find fping on system, must install fping package to use nodestat -f";
|
|
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
|
|
return $status;
|
|
}
|
|
open($fping, "$fpingcmd " . join(' ', @nodes) . " 2> /dev/null|") or die("Can't start fping: $!");
|
|
while (<$fping>) {
|
|
my %rsp;
|
|
my $node = $_;
|
|
$node =~ s/ .*//;
|
|
chomp $node;
|
|
if (/ is alive/) {
|
|
$status->{$node} = interrogate_node($node, $doreq, $p_tmp);
|
|
} elsif (/is unreachable/) {
|
|
$status->{$node}->{'status'} = "noping";
|
|
} elsif (/ address not found/) {
|
|
$status->{$node}->{'status'} = "nosuchhost";
|
|
}
|
|
}
|
|
}
|
|
|
|
return $status;
|
|
}
|
|
|
|
|
|
sub process_request_local_command {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $doreq = shift;
|
|
my $nodelist = shift;
|
|
my $p_tmp = shift;
|
|
my %cmdhash = %$p_tmp;
|
|
|
|
my @nodes = ();
|
|
if ($nodelist) { @nodes = @$nodelist; }
|
|
|
|
my $status = {};
|
|
|
|
if (@nodes > 0) {
|
|
foreach my $tmp_cmds (keys %cmdhash) {
|
|
my @cmds = split(',', $tmp_cmds);
|
|
my @apps = split(',', $cmdhash{$tmp_cmds});
|
|
my $index = 0;
|
|
foreach my $cmd (@cmds) {
|
|
my $nodes_string = join(',', @nodes);
|
|
my $ret = `$cmd $nodes_string`;
|
|
|
|
#print "ret=$ret\n";
|
|
if (($? == 0) && ($ret)) {
|
|
my @ret_array = split('\n', $ret);
|
|
foreach (@ret_array) {
|
|
my @a = split(':', $_);
|
|
chomp($a[1]);
|
|
if (exists($status->{ $a[0] })) {
|
|
$status->{ $a[0] } .= "," . $apps[$index] . "=" . $a[1];
|
|
} else {
|
|
$status->{ $a[0] } = $apps[$index] . "=" . $a[1];
|
|
}
|
|
}
|
|
}
|
|
$index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $status;
|
|
}
|
|
|
|
|
|
sub process_request_remote_command {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $doreq = shift;
|
|
my $nodelist = shift;
|
|
my $p_tmp = shift;
|
|
my %cmdhash = %$p_tmp;
|
|
my @nodes = ();
|
|
if ($nodelist) { @nodes = @$nodelist; }
|
|
|
|
my $status = {};
|
|
|
|
if (@nodes > 0) {
|
|
foreach my $tmp_cmds (keys %cmdhash) {
|
|
my @cmds = split(',', $tmp_cmds);
|
|
my @apps = split(',', $cmdhash{$tmp_cmds});
|
|
my $index = 0;
|
|
foreach my $cmd (@cmds) {
|
|
my @ret = xCAT::InstUtils->xcmd($callback, $doreq, "xdsh", \@nodes, $cmd, 1);
|
|
if (@ret) {
|
|
foreach (@ret) {
|
|
my @a = split(':', $_, 2);
|
|
chomp($a[1]); #remove newline
|
|
$a[1] =~ s/^\s+//; #remove leading white spaces
|
|
$a[1] =~ s/\s+$//; #remove tailing white spaces
|
|
|
|
if (exists($status->{ $a[0] })) {
|
|
$status->{ $a[0] } .= "," . $apps[$index] . "=" . $a[1];
|
|
} else {
|
|
$status->{ $a[0] } = $apps[$index] . "=" . $a[1];
|
|
}
|
|
}
|
|
}
|
|
$index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $status;
|
|
}
|
|
|
|
sub process_request {
|
|
my $request = shift;
|
|
my $callback = shift;
|
|
my $doreq = shift;
|
|
%nodesetstats = ();
|
|
my $command = $request->{command}->[0];
|
|
my $separator = "XXXXXYYYYYZZZZZ";
|
|
my $usefping;
|
|
if (ref $request->{arg}) {
|
|
@ARGV = @{ $request->{arg} };
|
|
my %opt;
|
|
GetOptions(\%opt, option_spec());
|
|
$usefping = $opt{f};
|
|
}
|
|
|
|
|
|
|
|
if ($command eq "nodestat_internal") {
|
|
|
|
#if ( -x '/usr/bin/nmap' ) {
|
|
# my %portservices = (
|
|
# '22' => 'sshd',
|
|
# '15002' => 'pbs',
|
|
# '8002' => 'xend',
|
|
# );
|
|
#
|
|
# return process_request_nmap($request, $callback, $doreq, $request->{node}, \%portservices);
|
|
# }
|
|
|
|
#handle ports and nodelist.status
|
|
my $status = {};
|
|
if (exists($request->{'portapps'})) {
|
|
for (my $i = 1 ; $i <= $request->{'portapps'}->[0] ; $i++) {
|
|
my %portservices = ();
|
|
my @apps = split(',', $request->{"portapps$i"}->[0]);
|
|
my @ports = split(',', $request->{ "portapps$i" . "port" }->[0]);
|
|
my $nodes = $request->{ "portapps$i" . "node" };
|
|
for (my $j = 0 ; $j < @ports ; $j++) {
|
|
$portservices{ $ports[$j] } = $apps[$j];
|
|
}
|
|
|
|
my $ret = {};
|
|
if (not $usefping and -x '/usr/bin/nmap') {
|
|
$ret = process_request_nmap($request, $callback, $doreq, $nodes, \%portservices);
|
|
} else {
|
|
$ret = process_request_port($request, $callback, $doreq, $nodes, \%portservices);
|
|
}
|
|
%$status = (%$status, %$ret);
|
|
}
|
|
}
|
|
|
|
|
|
#handle local commands
|
|
if (exists($request->{'cmdapps'})) {
|
|
for (my $i = 1 ; $i <= $request->{'cmdapps'}->[0] ; $i++) {
|
|
my %cmdhash = ();
|
|
my @apps = split(',', $request->{"cmdapps$i"}->[0]);
|
|
my @cmds = split(',', $request->{ "cmdapps$i" . "cmd" }->[0]);
|
|
my $nodes = $request->{ "cmdapps$i" . "node" };
|
|
for (my $j = 0 ; $j < @cmds ; $j++) {
|
|
$cmdhash{ $cmds[$j] } = $apps[$j];
|
|
}
|
|
|
|
my $ret = process_request_local_command($request, $callback, $doreq, $nodes, \%cmdhash);
|
|
|
|
#print Dumper($ret);
|
|
|
|
foreach my $node1 (keys(%$ret)) {
|
|
if (exists($status->{$node1})) {
|
|
my $appstatus = $status->{$node1}->{'appstatus'};
|
|
if ($appstatus) { $status->{$node1}->{'appstatus'} .= "," . $ret->{$node1}; }
|
|
else { $status->{$node1}->{'appstatus'} = $ret->{$node1}; }
|
|
my $appsd = $status->{$node1}->{'appsd'};
|
|
if ($appsd) { $status->{$node1}->{'appsd'} .= "," . $ret->{$node1}; }
|
|
else { $status->{$node1}->{'appsd'} = $ret->{$node1}; }
|
|
} else {
|
|
$status->{$node1}->{'appstatus'} = $ret->{$node1};
|
|
$status->{$node1}->{'appsd'} = $ret->{$node1};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#handle local l commands
|
|
if (exists($request->{'lcmdapps'})) {
|
|
for (my $i = 1 ; $i <= $request->{'lcmdapps'}->[0] ; $i++) {
|
|
my %cmdhash = ();
|
|
my @apps = split(',', $request->{"lcmdapps$i"}->[0]);
|
|
my @cmds = split(',', $request->{ "lcmdapps$i" . "cmd" }->[0]);
|
|
my $nodes = $request->{ "lcmdapps$i" . "node" };
|
|
for (my $j = 0 ; $j < @cmds ; $j++) {
|
|
$cmdhash{ $cmds[$j] } = $apps[$j];
|
|
}
|
|
|
|
my $ret = process_request_local_command($request, $callback, $doreq, $nodes, \%cmdhash);
|
|
|
|
foreach my $node1 (keys(%$ret)) {
|
|
if (exists($status->{$node1})) {
|
|
my $appstatus = $status->{$node1}->{'appstatus'};
|
|
if ($appstatus) { $status->{$node1}->{'appstatus'} .= "," . $ret->{$node1}; }
|
|
else { $status->{$node1}->{'appstatus'} = $ret->{$node1}; }
|
|
my $appsd = $status->{$node1}->{'appsd'};
|
|
if ($appsd) { $status->{$node1}->{'appsd'} .= "," . $ret->{$node1}; }
|
|
else { $status->{$node1}->{'appsd'} = $ret->{$node1}; }
|
|
} else {
|
|
$status->{$node1}->{'appstatus'} = $ret->{$node1};
|
|
$status->{$node1}->{'appsd'} = $ret->{$node1};
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#handle remote commands
|
|
if (exists($request->{'dcmdapps'})) {
|
|
for (my $i = 1 ; $i <= $request->{'dcmdapps'}->[0] ; $i++) {
|
|
my %dcmdhash = ();
|
|
my @apps = split(',', $request->{"dcmdapps$i"}->[0]);
|
|
my @dcmds = split(',', $request->{ "dcmdapps$i" . "dcmd" }->[0]);
|
|
my $nodes = $request->{ "dcmdapps$i" . "node" };
|
|
for (my $j = 0 ; $j < @dcmds ; $j++) {
|
|
$dcmdhash{ $dcmds[$j] } = $apps[$j];
|
|
}
|
|
|
|
my $ret = process_request_remote_command($request, $callback, $doreq, $nodes, \%dcmdhash);
|
|
foreach my $node1 (keys(%$ret)) {
|
|
if (exists($status->{$node1})) {
|
|
my $appstatus = $status->{$node1}->{'appstatus'};
|
|
if ($appstatus) { $status->{$node1}->{'appstatus'} .= "," . $ret->{$node1}; }
|
|
else { $status->{$node1}->{'appstatus'} = $ret->{$node1}; }
|
|
my $appsd = $status->{$node1}->{'appsd'};
|
|
if ($appsd) { $status->{$node1}->{'appsd'} .= "," . $ret->{$node1}; }
|
|
else { $status->{$node1}->{'appsd'} = $ret->{$node1}; }
|
|
} else {
|
|
$status->{$node1}->{'appstatus'} = $ret->{$node1};
|
|
$status->{$node1}->{'appsd'} = $ret->{$node1};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#nodestat_internal command the output, nodestat command will collect it
|
|
foreach my $node1 (sort keys(%$status)) {
|
|
my %rsp;
|
|
$rsp{name} = [$node1];
|
|
my $st = $status->{$node1}->{'status'};
|
|
my $ast = $status->{$node1}->{'appstatus'};
|
|
my $appsd = $status->{$node1}->{'appsd'};
|
|
$st = $st ? $st : '';
|
|
$ast = $ast ? $ast : '';
|
|
$appsd = $appsd ? $appsd : '';
|
|
|
|
$rsp{data}->[0] = "$st$separator$ast$separator$appsd";
|
|
$callback->({ node => [ \%rsp ] });
|
|
}
|
|
} else { #nodestat command
|
|
#first collect the status from the nodes
|
|
my $reqcopy = {%$request};
|
|
$reqcopy->{command}->[0] = 'nodestat_internal';
|
|
my $ret = xCAT::Utils->runxcmd($reqcopy, $doreq, 0, 1);
|
|
|
|
#print Dumper($ret);
|
|
my $status = {};
|
|
my @noping_nodes = ();
|
|
my $power = $request->{'power'}->[0];
|
|
foreach my $tmpdata (@$ret) {
|
|
if ($tmpdata =~ /([^:]+): (.*)$separator(.*)$separator(.*)/) {
|
|
|
|
#print "node=$1, status=$2, appstatus=$3, appsd=$4\n";
|
|
if ($status->{$1}->{'status'}) {
|
|
$status->{$1}->{'status'} = $status->{$1}->{'status'} . ",$2";
|
|
} else {
|
|
$status->{$1}->{'status'} = $2;
|
|
}
|
|
if ($status->{$1}->{'appstatus'}) {
|
|
$status->{$1}->{'appstatus'} = $status->{$1}->{'appstatus'} . ",$3";
|
|
} else {
|
|
$status->{$1}->{'appstatus'} = $3;
|
|
}
|
|
if ($status->{$1}->{'appsd'}) {
|
|
$status->{$1}->{'appsd'} = $status->{$1}->{'appsd'} . ",$4";
|
|
} else {
|
|
$status->{$1}->{'appsd'} = $4;
|
|
}
|
|
if (($power) && ($2 eq "noping")) {
|
|
push(@noping_nodes, $1);
|
|
}
|
|
} else {
|
|
my $rsp;
|
|
$rsp->{data}->[0] = "$tmpdata";
|
|
xCAT::MsgUtils->message("I", $rsp, $callback);
|
|
}
|
|
}
|
|
|
|
#print Dumper($status);
|
|
#get power status for noping nodes
|
|
if (($power) && (@noping_nodes > 0)) {
|
|
|
|
#print "noping_nodes=@noping_nodes\n";
|
|
my $ret = xCAT::Utils->runxcmd(
|
|
{
|
|
command => ['rpower'],
|
|
node => \@noping_nodes,
|
|
arg => ['stat']
|
|
},
|
|
$doreq, 0, 1);
|
|
|
|
foreach my $tmpdata (@$ret) {
|
|
if ($tmpdata =~ /([^:]+): (.*)/) {
|
|
$status->{$1}->{'status'} = "noping($2)";
|
|
} else {
|
|
my $rsp;
|
|
$rsp->{data}->[0] = "$tmpdata";
|
|
xCAT::MsgUtils->message("I", $rsp, $callback);
|
|
}
|
|
}
|
|
}
|
|
|
|
#print Dumper($request);
|
|
my $update = $request->{'update'}->[0];
|
|
my $quiet = $request->{'quiet'}->[0];
|
|
|
|
|
|
#show the output
|
|
if (!$quiet) {
|
|
foreach my $node1 (sort keys(%$status)) {
|
|
my %rsp;
|
|
$rsp{name} = [$node1];
|
|
my $st = $status->{$node1}->{'status'};
|
|
my $ast = $status->{$node1}->{'appstatus'};
|
|
if ($st) {
|
|
if ($st eq 'ping') { $st = $ast ? "$ast" : "$st"; }
|
|
else { $st = $ast ? "$st,$ast" : "$st"; }
|
|
} else {
|
|
$st = $ast;
|
|
}
|
|
$rsp{data}->[0] = $st;
|
|
$callback->({ node => [ \%rsp ] });
|
|
}
|
|
}
|
|
|
|
#update the nodelist table
|
|
if ($update) {
|
|
my $nodetab = xCAT::Table->new('nodelist', -create => 1);
|
|
if ($nodetab) {
|
|
my $status1 = {};
|
|
|
|
#get current values and compare with the new value to decide if update of db is necessary
|
|
my @nodes1 = keys(%$status);
|
|
my $stuff = $nodetab->getNodesAttribs(\@nodes1, [ 'node', 'status', 'appstatus' ]);
|
|
|
|
#get current local time
|
|
my (
|
|
$sec, $min, $hour, $mday, $mon,
|
|
$year, $wday, $yday, $isdst
|
|
)
|
|
= localtime(time);
|
|
my $currtime = sprintf("%02d-%02d-%04d %02d:%02d:%02d",
|
|
$mon + 1, $mday, $year + 1900,
|
|
$hour, $min, $sec);
|
|
|
|
foreach my $node1 (@nodes1) {
|
|
my $oldstatus = $stuff->{$node1}->[0]->{status};
|
|
my $newstatus = $status->{$node1}->{status};
|
|
if ($newstatus) {
|
|
if ((!$oldstatus) || ($newstatus ne $oldstatus)) {
|
|
$status1->{$node1}->{status} = $newstatus;
|
|
$status1->{$node1}->{statustime} = $currtime;
|
|
}
|
|
}
|
|
else {
|
|
if ($oldstatus) {
|
|
$status1->{$node1}->{status} = "";
|
|
$status1->{$node1}->{statustime} = "";
|
|
}
|
|
}
|
|
|
|
if ($newstatus =~ /noping/) {
|
|
$status1->{$node1}->{appstatus} = "";
|
|
} else {
|
|
my $oldappstatus = $stuff->{$node1}->[0]->{'appstatus'};
|
|
my $newappstatus = $status->{$node1}->{'appsd'};
|
|
while ($newappstatus =~ /(\w+)\=(\w+)/) {
|
|
my $tmp1 = $1;
|
|
my $tmp2 = $2;
|
|
if ($oldappstatus) {
|
|
if ($oldappstatus =~ /$tmp1\=/) {
|
|
$oldappstatus =~ s/$tmp1\=\w+/$tmp1\=$tmp2/g;
|
|
} else {
|
|
$oldappstatus = $oldappstatus . "\,$tmp1\=$tmp2";
|
|
}
|
|
} else {
|
|
$oldappstatus = "$tmp1\=$tmp2";
|
|
}
|
|
$newappstatus =~ s/(\w+)\=(\w+)//;
|
|
}
|
|
$status1->{$node1}->{appstatus} = $oldappstatus;
|
|
}
|
|
$status1->{$node1}->{appstatustime} = $currtime;
|
|
}
|
|
|
|
#print Dumper($status1);
|
|
$nodetab->setNodesAttribs($status1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub usage
|
|
{
|
|
my $cb = shift;
|
|
my $retcode=shift;
|
|
my $rsp = {};
|
|
$rsp->{data}->[0] = "Usage:";
|
|
$rsp->{data}->[1] = " nodestat [noderange] [-m|--usemon] [-p|powerstat] [-f|--usefping] [-u|--updatedb]";
|
|
$rsp->{data}->[2] = " nodestat [-h|--help|-v|--version]";
|
|
if($retcode){
|
|
$rsp->{errorcode}->[0]=$retcode;
|
|
}
|
|
xCAT::MsgUtils->message("I", $rsp, $cb);
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getStatusMonsettings
|
|
This function goes to the monsetting table to retrieve the settings related to
|
|
the node status and app status monitoring.
|
|
Arguments:
|
|
none.
|
|
Returns:
|
|
a hash that has settings from the monsetting table for node status and
|
|
app status monitoring. For example:
|
|
( 'APPS'=>[ll,gpfs],
|
|
'll' =>
|
|
{
|
|
'group' => 'service,compute',
|
|
'port' => '5001'
|
|
},
|
|
'gpfs' =>
|
|
{
|
|
'group' => 'service',
|
|
'cmd' => '/tmp/gpfscmd'
|
|
};
|
|
)
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub getStatusMonsettings {
|
|
my %apps = ();
|
|
my $tab = xCAT::Table->new('monsetting');
|
|
if (defined($tab)) {
|
|
my ($ent) = $tab->getAttribs({ name => 'xcatmon', key => 'apps' }, 'value');
|
|
if (defined($ent)) {
|
|
my $tmp_list = $ent->{value};
|
|
if ($tmp_list) {
|
|
my @applist = split(',', $tmp_list);
|
|
foreach my $app (@applist) {
|
|
$apps{$app} = {};
|
|
}
|
|
$apps{'APPS'} = \@applist;
|
|
my @results = $tab->getAttribs({ name => 'xcatmon' }, 'key', 'value');
|
|
if (@results) {
|
|
foreach (@results) {
|
|
my $key = $_->{key};
|
|
my $value = $_->{value};
|
|
if (exists($apps{$key})) {
|
|
my @tem_value = split(',', $value);
|
|
foreach my $pair (@tem_value) {
|
|
my @tmp_action = split('=', $pair);
|
|
if (exists($apps{$key}->{ $tmp_action[0] })) {
|
|
$apps{$key}->{ $tmp_action[0] } = $apps{$key}->{ $tmp_action[0] } . "," . $tmp_action[1];
|
|
} else {
|
|
$apps{$key}->{ $tmp_action[0] } = $tmp_action[1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return %apps;
|
|
|
|
}
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 getNodeStatusAndAppstatus
|
|
This function goes to the xCAT nodelist table to retrieve the saved node status and appstatus
|
|
for all the node that are managed by local nodes.
|
|
Arguments:
|
|
nodelist--- an array of nodes
|
|
Returns:
|
|
a hash pointer that has the node status and appstatus. The format is:
|
|
{ node1=> {
|
|
status=>'active',appstatus=>'sshd=up,ll=up,gpfs=down'
|
|
} ,
|
|
node2=> {
|
|
status=>'active',appstatus=>'sshd=up,ll=down,gpfs=down'
|
|
}
|
|
}
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
sub getMonNodesStatusAndAppStatus {
|
|
my @nodes = @_;
|
|
|
|
my %status = ();
|
|
my $table = xCAT::Table->new("nodelist", -create => 1);
|
|
my $tabdata = $table->getNodesAttribs(\@nodes, [ 'node', 'status', 'appstatus' ]);
|
|
foreach my $node (@nodes) {
|
|
my $tmp1 = $tabdata->{$node}->[0];
|
|
if ($tmp1) {
|
|
$status{$node}->{status} = $tmp1->{status};
|
|
$status{$node}->{appstatus} = $tmp1->{appstatus};
|
|
}
|
|
}
|
|
return %status;
|
|
}
|
|
|
|
|
|
|
|
1;
|