2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-24 20:52:08 +00:00
xcat-core/xCAT-probe/subcmds/clusterstatus
zet809 852e996eff enhance clusterstatus to report cluster status (#3900)
* enhance clusterstatus to report cluster status

* modify usage for clusterstatus
2017-09-15 15:58:38 +08:00

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;