mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-03 21:02:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			237 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env perl
 | 
						|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
						|
#Note, this pping still frontends fping.  I think it would be possible to write a perl equivalent, but
 | 
						|
#I've not had the time.  Net::Ping shows perl code I could see being adapted for a somewhat
 | 
						|
#asynchronous ICMP ping (the tcp syn is interesting, but far too limited, and that is currently the only async
 | 
						|
#method Net::Ping provides.
 | 
						|
BEGIN
 | 
						|
{
 | 
						|
    $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr';
 | 
						|
}
 | 
						|
use strict;
 | 
						|
use lib "$::XCATROOT/lib/perl";
 | 
						|
 | 
						|
use xCAT::Utils;
 | 
						|
use xCAT::TableUtils;
 | 
						|
use POSIX qw(:signal_h :errno_h :sys_wait_h);
 | 
						|
use IO::Socket::SSL;
 | 
						|
use XML::Simple;
 | 
						|
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
 | 
						|
 | 
						|
#use Data::Dumper;
 | 
						|
use IO::Handle;
 | 
						|
use IO::Select;
 | 
						|
use Getopt::Long;
 | 
						|
 | 
						|
my $USAGE = "Usage: pping [-i|--interface interfaces][-f|--use_fping] noderange
 | 
						|
       pping -h|--help
 | 
						|
       pping -v|--version\n";
 | 
						|
 | 
						|
my $interface;
 | 
						|
 | 
						|
# Parse the options
 | 
						|
require Getopt::Long;
 | 
						|
Getopt::Long::Configure("bundling");
 | 
						|
if (!GetOptions(
 | 
						|
        'f|use_fping'   => \$::USE_FPING,
 | 
						|
        'h|help'        => \$::HELP,
 | 
						|
        'v|version'     => \$::VERSION,
 | 
						|
        'X|noexpand'    => \$::NOEXPAND,
 | 
						|
        'i|interface=s' => \$interface))
 | 
						|
{
 | 
						|
    print "$USAGE";
 | 
						|
    exit 1;
 | 
						|
}
 | 
						|
 | 
						|
if ($::HELP) { print "$USAGE"; exit 0 }
 | 
						|
if ($::VERSION) { print xCAT::Utils->Version() . "\n"; exit 0 }
 | 
						|
my $xcathost = 'localhost:3001';
 | 
						|
if ($ENV{XCATHOST}) {
 | 
						|
    $xcathost = $ENV{XCATHOST};
 | 
						|
}
 | 
						|
 | 
						|
unless (@ARGV) {
 | 
						|
    print "$USAGE";
 | 
						|
    exit(1);
 | 
						|
}
 | 
						|
my $noderange = $ARGV[0];
 | 
						|
my @nodes     = ();
 | 
						|
my $cmd       = "id -u";
 | 
						|
my $userid    = xCAT::Utils->runcmd("$cmd", -1);
 | 
						|
 | 
						|
if ($::NOEXPAND) { # this is when ppping is calling us and has already expanded the noderange
 | 
						|
    @nodes = split(/,/, $noderange);
 | 
						|
}
 | 
						|
else { # the normal case of the user running the cmd - expand the noderange using xcatd
 | 
						|
    my %sslargs;
 | 
						|
    if (defined($ENV{'XCATSSLVER'})) {
 | 
						|
        $sslargs{SSL_version} = $ENV{'XCATSSLVER'};
 | 
						|
    }
 | 
						|
 | 
						|
    my $client = IO::Socket::SSL->new(
 | 
						|
        PeerAddr        => $xcathost,
 | 
						|
        SSL_key_file    => xCAT::Utils->getHomeDir() . "/.xcat/client-cred.pem",
 | 
						|
        SSL_cert_file   => xCAT::Utils->getHomeDir() . "/.xcat/client-cred.pem",
 | 
						|
        SSL_ca_file     => xCAT::Utils->getHomeDir() . "/.xcat/ca.pem",
 | 
						|
        SSL_use_cert    => 1,
 | 
						|
        SSL_verify_mode => SSL_VERIFY_PEER,
 | 
						|
        SSL_verifycn_scheme => "none",
 | 
						|
        %sslargs,
 | 
						|
    );
 | 
						|
    die "Connection failure: $!\n" unless ($client);
 | 
						|
    my %cmdref = (command => 'noderange', noderange => $noderange);
 | 
						|
    $SIG{ALRM} = sub { die "No response getting noderange" };
 | 
						|
    alarm(15);
 | 
						|
    print $client XMLout(\%cmdref, RootName => 'xcatrequest', NoAttr => 1, KeyAttr => []);
 | 
						|
    alarm(15);
 | 
						|
    my $response = "";
 | 
						|
 | 
						|
    while (<$client>) {
 | 
						|
        alarm(0);
 | 
						|
        $response .= $_;
 | 
						|
        if ($response =~ m/<\/xcatresponse>/) {
 | 
						|
            my $rsp = XMLin($response, ForceArray => ['node']);
 | 
						|
            $response = '';
 | 
						|
            if ($rsp->{warning}) {
 | 
						|
                printf "Warning: " . $rsp->{warning} . "\n";
 | 
						|
            }
 | 
						|
            if ($rsp->{error}) {
 | 
						|
                die("ERROR: " . $rsp->{error} . "\n");
 | 
						|
            } elsif ($rsp->{node}) {
 | 
						|
                @nodes = @{ $rsp->{node} };
 | 
						|
            }
 | 
						|
            if ($rsp->{serverdone}) {
 | 
						|
                last;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    close($client);
 | 
						|
}    # end of else that expands the noderange using xcatd
 | 
						|
 | 
						|
unless (scalar(@nodes)) {
 | 
						|
    exit 1;
 | 
						|
}
 | 
						|
 | 
						|
# I think this was only needed when we forked ping ourselves
 | 
						|
#my $children = 0;
 | 
						|
#my $inputs = new IO::Select;
 | 
						|
#$SIG{CHLD} = sub { while (waitpid(-1,WNOHANG) > 0) { $children--; } };
 | 
						|
 | 
						|
my $usenmap = (-x '/usr/bin/nmap' or -x '/usr/local/bin/nmap');
 | 
						|
if ($::USE_FPING) {    # Use fping instead of nmap
 | 
						|
    $usenmap = 0;
 | 
						|
}
 | 
						|
 | 
						|
my @interfaces;
 | 
						|
if ($interface) { @interfaces = split(/,/, $interface); }
 | 
						|
else            { $interfaces[0] = ''; }
 | 
						|
 | 
						|
# Do the pings to the nodes for each interface in sequence.  We could consider doing all the interfaces
 | 
						|
# in parallel, but then the output would get all mixed up and be confusing for the user.
 | 
						|
foreach my $interf (@interfaces) {
 | 
						|
    my $noderef;
 | 
						|
    if ($interf) {
 | 
						|
 | 
						|
        # make a copy of the node list and add the interface on
 | 
						|
        $noderef = [@nodes];
 | 
						|
        foreach (@$noderef) {
 | 
						|
            s/-hf\d$//;
 | 
						|
            s/$/-$interf/;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        $noderef = \@nodes;    # use the original node list
 | 
						|
    }
 | 
						|
 | 
						|
    if   ($usenmap) { nmap_pping($noderef); }
 | 
						|
    else            { fping_pping($noderef); }
 | 
						|
}
 | 
						|
 | 
						|
sub fping_pping {
 | 
						|
    my $nodes    = shift;
 | 
						|
    my $master   = xCAT::TableUtils->get_site_Master();
 | 
						|
    my $masterip = xCAT::NetworkUtils->getipaddr($master);
 | 
						|
    if ($masterip =~ /:/)      #IPv6, needs fping6 support
 | 
						|
    {
 | 
						|
        if (!-x '/usr/bin/fping6')
 | 
						|
        {
 | 
						|
            print "fping6 is not availabe for IPv6 ping.\n";
 | 
						|
            exit 1;
 | 
						|
        }
 | 
						|
        open(FPING, "fping6 " . join(' ', @$nodes) . " 2>&1 |") or die("Cannot open fping pipe: $!");
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if (!-x '/usr/bin/fping' and !-x '/usr/sbin/fping')
 | 
						|
        {
 | 
						|
            print "fping is not available, please install missing package fping.\n";
 | 
						|
            exit 1;
 | 
						|
        }
 | 
						|
        open(FPING, "fping " . join(' ', @$nodes) . " 2>&1 |") or die("Cannot open fping pipe: $!");
 | 
						|
    }
 | 
						|
    while (<FPING>) {
 | 
						|
        if ($_ =~ /is unreachable/) {
 | 
						|
            s/ is unreachable/: noping/;
 | 
						|
        } elsif ($_ =~ /is alive/) {
 | 
						|
            s/ is alive/: ping/;
 | 
						|
        } elsif ($_ =~ /address not found/) {
 | 
						|
            s/ address not found/: noping/;
 | 
						|
        }
 | 
						|
        print $_;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
sub nmap_pping {
 | 
						|
    my $nodes = shift;
 | 
						|
    my %deadnodes;
 | 
						|
    my @nmap_options;
 | 
						|
    my $more_options;
 | 
						|
    my $tcmd;
 | 
						|
    foreach (@$nodes) {
 | 
						|
        $deadnodes{$_} = 1;
 | 
						|
    }
 | 
						|
    if ($userid != 0) {
 | 
						|
        $tcmd = "tabdump site|grep nmapoptions|awk -F, '{print $2}'|sed -e 's/\"//g'|awk -F, '{print $1}'";
 | 
						|
        $more_options = xCAT::Utils->runcmd($tcmd, -1);
 | 
						|
    } else {
 | 
						|
 | 
						|
        # get additional options from site table
 | 
						|
        @nmap_options = xCAT::TableUtils->get_site_attribute("nmapoptions");
 | 
						|
        $more_options = $nmap_options[0];
 | 
						|
    }
 | 
						|
    # Added port 22 for unprivileged case (#4324)
 | 
						|
    open(NMAP, "nmap -PE --system-dns --send-ip -sP --unprivileged -PA80,443,22 $more_options " . join(' ', @$nodes) . " 2> /dev/null|") or die("Cannot open nmap pipe: $!");
 | 
						|
    my $node;
 | 
						|
    while (<NMAP>) {
 | 
						|
        if (/Host (.*) \(.*\) appears to be up/) {
 | 
						|
            $node = $1;
 | 
						|
            unless ($deadnodes{$node}) {
 | 
						|
                foreach (keys %deadnodes) {
 | 
						|
                    if ($node =~ /^$_\./) {
 | 
						|
                        $node = $_;
 | 
						|
                        last;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            delete $deadnodes{$node};
 | 
						|
            print "$node: ping\n" if ($node);
 | 
						|
        } elsif (/Nmap scan report for ([^ ]*) /) {
 | 
						|
            $node = $1;
 | 
						|
        } elsif (/Host is up./) {
 | 
						|
            unless ($deadnodes{$node}) {
 | 
						|
                foreach (keys %deadnodes) {
 | 
						|
                    if ($node =~ /^$_\./) {
 | 
						|
                        $node = $_;
 | 
						|
                        last;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            delete $deadnodes{$node};
 | 
						|
            print "$node: ping\n" if ($node);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    foreach (sort keys %deadnodes) {
 | 
						|
        print "$_: noping\n";
 | 
						|
    }
 | 
						|
}
 |