mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-24 20:52:08 +00:00
333 lines
10 KiB
Perl
Executable File
333 lines
10 KiB
Perl
Executable File
#! /usr/bin/perl
|
|
# IBM(c) 2016 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr'; }
|
|
|
|
use lib "$::XCATROOT/probe/lib/perl";
|
|
use probe_utils;
|
|
use File::Basename;
|
|
use Net::Ping;
|
|
use Getopt::Long qw(:config no_ignore_case);
|
|
|
|
use Data::Dumper;
|
|
use warnings;
|
|
|
|
my $program_name = basename("$0");
|
|
my $help;
|
|
my $noderange = undef;
|
|
my $test;
|
|
my $output = "stdout";
|
|
my $verbose = 0;
|
|
my $rst = 0;
|
|
my $interval = 5;
|
|
my $terminal = 0;
|
|
my $timeout = 0;
|
|
my $start_time;
|
|
|
|
#-----------------------------
|
|
# To store the node number of a specified type
|
|
# May like this:
|
|
# $type_nodesnum{pdu} = 2;
|
|
# {switch} = 3;
|
|
# {node} = 10;
|
|
#-----------------------------
|
|
my %type_nodesnum = ();
|
|
|
|
#-----------------------------
|
|
# To store the type, state hash
|
|
# May like this:
|
|
# $state_node_hash{pdu}{state1}{pdu1} = 1;
|
|
# $state_node_hash{pdu}{state1}{pdu2} = 1;
|
|
# $state_node_hash{pdu}{state2}{pdu3} = 1;
|
|
# $state_node_hash{pdu}{state3}{pdu4} = 1;
|
|
# The state include but not limited to below:
|
|
# matching --> matched --> configured (For PDU/Switch)
|
|
# matching --> matched --> installing --> booting --> booted
|
|
# matching --> matched --> booting --> installing --> xxx --> booted
|
|
# The terminal state is configured(For PDU/Switch) or booted(for Node)
|
|
#-----------------------------
|
|
my %state_node_hash = ();
|
|
|
|
# $state_node_hash{pdu}{state1}{number} = xx;
|
|
my %state_node_number = ();
|
|
|
|
#----------------------------
|
|
# To store the node based current state
|
|
# May like this:
|
|
# $node_info{node1}{state} = "install";
|
|
# $node_info{node1}{type} = "node";
|
|
#----------------------------
|
|
my %node_info = ();
|
|
|
|
#---------------------------
|
|
# To store nodes who haven't finished the status
|
|
#---------------------------
|
|
my %unfinished_nodes = ();
|
|
my %unmatched_nodes = ();
|
|
|
|
$::USAGE = "Usage:
|
|
$program_name -h
|
|
$program_name [-n noderange] [-V|--verbose] [-i|--interval <seconds>] [--timeout <seconds>]
|
|
|
|
Description:
|
|
Use this command to get a summary of the cluster.
|
|
|
|
Options:
|
|
-h : Get usage information of $program_name
|
|
-n : Range of nodes to check. All node objects will be used if not specified.
|
|
-i : The interval for screen refreshing, unit is second(s), 5 seconds by default.
|
|
-V : To print additional debug information.
|
|
--timeout: The timout if not all nodes finish, unit is second(s), no timeout by default.
|
|
";
|
|
|
|
#-------------------------------------
|
|
# main process
|
|
#-------------------------------------
|
|
if (
|
|
!GetOptions("--help|h" => \$help,
|
|
"T" => \$test,
|
|
"V|verbose" => \$VERBOSE,
|
|
"d|discovery" => \$DISCOVERY,
|
|
"g|groupcount" => \$GROUPCOUNT,
|
|
"i|interval=s" => \$interval,
|
|
"timeout=s" => \$timeout,
|
|
"n=s" => \$noderange))
|
|
{
|
|
probe_utils->send_msg("$output", "f", "Invalid parameter for $program_name");
|
|
probe_utils->send_msg("$output", "d", "$::USAGE");
|
|
exit 1;
|
|
}
|
|
|
|
if ($help) {
|
|
if ($output ne "stdout") {
|
|
probe_utils->send_msg("$output", "d", "$::USAGE");
|
|
} else {
|
|
print "$::USAGE";
|
|
}
|
|
exit 0;
|
|
}
|
|
|
|
if ($test) {
|
|
probe_utils->send_msg("$output", "o", "Use this command to get node summary in the cluster.");
|
|
exit 0;
|
|
}
|
|
|
|
if (scalar(@ARGV) >= 1) {
|
|
|
|
# After processing all the expected flags and arguments,
|
|
# there is still left over stuff on the command line
|
|
probe_utils->send_msg("$output", "f", "Invalid flag or parameter: @ARGV");
|
|
probe_utils->send_msg("$output", "d", "$::USAGE");
|
|
exit 1;
|
|
}
|
|
if (!$DISCOVERY and !$GROUPCOUNT) {
|
|
if(!defined($noderange)) {
|
|
$noderange = "all";
|
|
}
|
|
} else {
|
|
if (!defined($noderange)) {
|
|
$noderange = "compute";
|
|
}
|
|
check_for_discovered_nodes() if ($DISCOVERY);
|
|
groupcount_nodes() if ($GROUPCOUNT);
|
|
exit 0;
|
|
}
|
|
|
|
$SIG{TERM} = $SIG{INT} = sub {
|
|
$terminal = 1;
|
|
};
|
|
unless ($interval) {
|
|
$interval = 5;
|
|
}
|
|
|
|
&check_nodes_attributes();
|
|
$start_time = time;
|
|
while (1) {
|
|
update_nodes_info();
|
|
alarm_output(1);
|
|
if ($terminal) {
|
|
alarm_output(0);
|
|
last;
|
|
}
|
|
if ($timeout and (time() - $start_time > $timeout)) {
|
|
alarm_output(0);
|
|
last;
|
|
}
|
|
sleep $interval;
|
|
}
|
|
exit 0;
|
|
# Check for node definitions with MAC address defined
|
|
sub check_for_discovered_nodes {
|
|
my $na = "N/A";
|
|
my $rc = 0;
|
|
|
|
my $all_nodes_mac = `lsdef -i mac -c $noderange 2> /dev/null`;
|
|
chomp($all_nodes_mac);
|
|
my @all_nodes_mac_lines = split("[\n\r]", $all_nodes_mac);
|
|
|
|
if ($all_nodes_mac =~ /Usage:/) {
|
|
|
|
# lsdef command displayed a Usage message. Must be some noderange formatting problem.
|
|
# Issue a warning and exit.
|
|
probe_utils->send_msg("$output", "w", "Can not get a list of nodes from specified noderange.");
|
|
return 1;
|
|
}
|
|
|
|
if (scalar(@all_nodes_mac_lines) <= 0) {
|
|
|
|
# There were no nodes matching the noderange. Issue a warning and exit.
|
|
probe_utils->send_msg("$output", "w", "No nodes matching the noderange were found.");
|
|
return 1;
|
|
}
|
|
|
|
# Go through the list of nodes and count how many have mac value
|
|
my $mac_counter=0;
|
|
foreach (@all_nodes_mac_lines) {
|
|
# probe_utils->send_msg("$output", "d", "Processing $_.") if ($VERBOSE);
|
|
my ($node_name, $value) = split ":", $_;
|
|
my ($mac_name, $mac_value) = split "=", $value;
|
|
if ($mac_value) {
|
|
# mac if set for the node
|
|
$mac_counter++;
|
|
probe_utils->send_msg("$output", "d", "($mac_counter) $_") if ($VERBOSE);
|
|
}
|
|
}
|
|
my $percent = sprintf("%.2f", (($mac_counter / scalar(@all_nodes_mac_lines)) * 100));
|
|
|
|
probe_utils->send_msg("$output", "o", "$mac_counter out of " . scalar(@all_nodes_mac_lines) . " in the noderange \"$noderange\" have been discovered ($percent/%)");
|
|
return $rc;
|
|
}
|
|
|
|
sub groupcount_nodes {
|
|
my $na = "N/A";
|
|
my $rc = 0;
|
|
|
|
probe_utils->send_msg("$output", "w", "Group count function is not yet implemented.");
|
|
return $rc;
|
|
}
|
|
|
|
sub alarm_output {
|
|
my $flag = shift;
|
|
if ($flag) {
|
|
probe_utils->send_msg("$output", "xx", `clear`);
|
|
my $time_elapsed = time - $start_time;
|
|
probe_utils->send_msg("$output", "xx", "====".localtime()."($time_elapsed seconds Elapsed)");
|
|
} else {
|
|
probe_utils->send_msg("$output", "xx", "\nThe cluster state===============================");
|
|
}
|
|
foreach my $type (keys(%state_node_hash)) {
|
|
unless ($type_nodesnum{$type}) {
|
|
probe_utils->send_msg("$output", "w", "$type Total number: $type_nodesnum{$type}");
|
|
next;
|
|
}
|
|
probe_utils->send_msg("$output", "xx", "$type(Total: $type_nodesnum{$type})--------------------------");
|
|
foreach my $state (keys(%{$state_node_hash{$type}})) {
|
|
my $node_number = scalar(keys %{$state_node_hash{$type}{$state}});
|
|
if ($flag) {
|
|
my $number = sprintf("%.2f", $node_number * 100.0/ $type_nodesnum{$type});
|
|
probe_utils->send_msg("$output", "xx", "\t$state : $node_number($number%)");
|
|
} else {
|
|
probe_utils->send_msg("$output", "xx", "\t$state($node_number): ". join(",",keys %{$state_node_hash{$type}{$state}}) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub update_nodes_info {
|
|
if (keys(%unmatched_nodes)) {
|
|
my $unmatched_noderange = join(",", keys(%unmatched_nodes));
|
|
my @unmatched_nodes_attributes = `lsdef -i mac -c $unmatched_noderange 2> /dev/null`;
|
|
foreach (@unmatched_nodes_attributes) {
|
|
if (/^(.*):\s*mac=(.*)$/) {
|
|
if ($2) {
|
|
update_node_info($1, "Matched");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (keys(%unfinished_nodes)) {
|
|
my $unfinished_noderange = join(",", keys(%unfinished_nodes));
|
|
my @unfinished_nodes_attributes = `lsdef -i status -c $unfinished_noderange 2> /dev/null`;
|
|
foreach (@unfinished_nodes_attributes) {
|
|
if (/^(.*):\s*status=(.*)$/) {
|
|
if ($2) {
|
|
update_node_info($1, "$2");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unless(scalar keys(%unfinished_nodes)) {
|
|
$terminal = 1;
|
|
}
|
|
}
|
|
|
|
sub update_node_info {
|
|
my $node = shift;
|
|
my $state = shift;
|
|
my $node_type = $node_info{$node}{type};
|
|
my $node_state = $node_info{$node}{state};
|
|
if ($state and $state ne '') {
|
|
if (exists($unmatched_nodes{$node})) {
|
|
delete($unmatched_nodes{$node});
|
|
$unfinished_nodes{$node} = 1;
|
|
}
|
|
}
|
|
if ($state eq $node_state) {
|
|
return;
|
|
}
|
|
|
|
if (exists($state_node_hash{$node_type}{$node_state}{$node})) {
|
|
delete($state_node_hash{$node_type}{$node_state}{$node});
|
|
}
|
|
unless (scalar keys ($state_node_hash{$node_type}{$node_state})) {
|
|
delete($state_node_hash{$node_type}{$node_state});
|
|
}
|
|
|
|
$state_node_hash{$node_type}{$state}{$node} = 1;
|
|
|
|
$node_info{$node}{state} = $state;
|
|
if ($state eq 'booted' or $state eq 'configured') {
|
|
delete $unfinished_nodes{$node};
|
|
}
|
|
}
|
|
sub check_nodes_attributes {
|
|
my @nodes_attributes = `lsdef -i status,mac,mgt -c $noderange 2> /dev/null`;
|
|
my %nodehash = ();
|
|
foreach (@nodes_attributes) {
|
|
if (/^(.*):\s*([^=]*)=(.*)$/) {
|
|
$nodehash{$1}{$2}=$3;
|
|
}
|
|
}
|
|
foreach (keys %nodehash) {
|
|
if (!defined($nodehash{$_}{mgt})) {
|
|
probe_utils->send_msg("$output", "w", "No 'mgt' set for node:$_");
|
|
next;
|
|
}
|
|
if ($nodehash{$_}{status}) {
|
|
$node_info{$_}{state} = $nodehash{$_}{status};
|
|
$unfinished_nodes{$_} = 1;
|
|
} elsif ($nodehash{$_}{mac}) {
|
|
$node_info{$_}{state} = "Matched";
|
|
$unfinished_nodes{$_} = 1;
|
|
} else {
|
|
$node_info{$_}{state} = "matching";
|
|
$unmatched_nodes{$_} = 1;
|
|
}
|
|
if ($nodehash{$_}{mgt} eq 'pdu') {
|
|
$node_info{$_}{type} = 'pdu';
|
|
} elsif($nodehash{$_}{mgt} eq 'switch') {
|
|
$node_info{$_}{type} = 'switch';
|
|
} else {
|
|
$node_info{$_}{type} = 'node';
|
|
}
|
|
my $node_type = $node_info{$_}{type};
|
|
if (!exists($type_nodesnum{$node_type})) {
|
|
$type_nodesnum{$node_type} = 1;
|
|
} else {
|
|
$type_nodesnum{$node_type} += 1;
|
|
}
|
|
$state_node_hash{$node_type}{$node_info{$_}{state}}{$_} = 1;
|
|
}
|
|
}
|
|
exit 0;
|