mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 03:12:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1330 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			1330 lines
		
	
	
		
			48 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 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
 | |
|         $::UPDATE = 0;
 | |
|         $::QUITE  = 0;
 | |
|         $::MON    = 0;
 | |
|         $::POWER  = 0;
 | |
| 
 | |
|         #Getopt::Long::Configure("posix_default");
 | |
|         #Getopt::Long::Configure("no_gnu_compat");
 | |
|         Getopt::Long::Configure("bundling");
 | |
|         $Getopt::Long::ignorecase = 0;
 | |
|         if (!GetOptions(
 | |
|                 'm|usemon' => \$::MON,
 | |
|                 'q|quite' => \$::QUITE, #this is a internal flag used by monitoring
 | |
|                 'u|updatedb'  => \$::UPDATE,
 | |
|                 'p|powerstat' => \$::POWER,
 | |
|                 'h|help'      => \$::HELP,
 | |
|                 'v|version'   => \$::VERSION))
 | |
|         {
 | |
|             &usage($cb,1);
 | |
|             return (1);
 | |
|         }
 | |
|         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->{'quite'}->[0]  = $::QUITE;
 | |
|         $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;
 | |
|         open($fping, "fping " . 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} };
 | |
|         GetOptions(
 | |
|             'f|useping' => \$usefping
 | |
|         );
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
|     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 $quite  = $request->{'quite'}->[0];
 | |
| 
 | |
| 
 | |
|         #show the output
 | |
|         if (!$quite) {
 | |
|             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;
 |