xcat-core/perl-xCAT/xCAT/PPCscan.pm

679 lines
20 KiB
Perl
Raw Normal View History

# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::PPCscan;
use strict;
use Getopt::Long;
use Socket;
use XML::Simple;
$XML::Simple::PREFERRED_PARSER='XML::Parser';
use xCAT::PPCcli qw(SUCCESS EXPECT_ERROR RC_ERROR NR_ERROR);
use xCAT::PPCdb;
use xCAT::GlobalDef;
use xCAT::Usage;
use xCAT::NetworkUtils;
##############################################
# Globals
##############################################
my @header = (
["type", "%-8s" ],
["name", "placeholder" ],
["id", "%-8s" ],
["type-model", "%-12s" ],
["serial-number", "%-15s" ],
["side", "%-6s\n" ]);
my @attribs = qw(nodetype node id mtm serial side hcp pprofile parent groups mgt cons);
my %nodetype = (
fsp => $::NODETYPE_FSP,
bpa => $::NODETYPE_BPA,
lpar =>"$::NODETYPE_LPAR,$::NODETYPE_OSI"
);
##########################################################################
# Parse the command line for options and operands
##########################################################################
sub parse_args {
my $request = shift;
my %opt = ();
my $cmd = $request->{command};
my $args = $request->{arg};
#############################################
# Responds with usage statement
#############################################
local *usage = sub {
my $usage_string = xCAT::Usage->getUsage($cmd);
return( [ $_[0], $usage_string] );
};
#############################################
# Process command-line arguments
#############################################
if ( !defined( $args )) {
$request->{method} = $cmd;
return( \%opt );
}
#############################################
# Checks case in GetOptions, allows opts
# to be grouped (e.g. -vx), and terminates
# at the first unrecognized option.
#############################################
@ARGV = @$args;
$Getopt::Long::ignorecase = 0;
Getopt::Long::Configure( "bundling" );
if ( !GetOptions( \%opt, qw(V|Verbose u w x z) )){
return( usage() );
}
####################################
# Check for "-" with no option
####################################
if ( grep(/^-$/, @ARGV )) {
return(usage( "Missing option: -" ));
}
####################################
# Check for an argument
####################################
if ( defined( $ARGV[0] )) {
return(usage( "Invalid Argument: $ARGV[0]" ));
}
#############################################
# Check for mutually-exclusive formatting
#############################################
if (( exists($opt{x}) + exists($opt{z})) > 1 ) {
return( usage() );
}
#############################################
# Check for mutually-exclusive flags
#############################################
if (( exists($opt{u}) + exists($opt{w})) > 1 ) {
return(usage( "Flag -u cannot be used with flag -w"));
}
####################################
# No operands - add command name
####################################
$request->{method} = $cmd;
return( \%opt );
}
##########################################################################
# Returns short-hostname given an IP
##########################################################################
sub getshorthost {
my $ip = shift;
my $host = xCAT::NetworkUtils->gethostname($ip);
if ( $host and !$! ) {
##############################
# Get short-hostname
##############################
if ( $host =~ /([^\.]+)\./ ) {
return($1);
}
}
##################################
# Failed
##################################
return undef;
}
##########################################################################
# Returns I/O bus information
##########################################################################
sub enumerate {
my $exp = shift;
my $hwtype = @$exp[2];
my $server = @$exp[3];
my @values = ();
my %cage = ();
my %hwconn = ();
my $Rc;
my $filter;
#########################################
# Get hardware control point info
#########################################
{
my $hcp = xCAT::PPCcli::lshmc( $exp );
$Rc = shift(@$hcp);
#########################################
# Return error
#########################################
if ( $Rc != SUCCESS ) {
return( @$hcp[0] );
}
#########################################
# Success
#########################################
my ($model,$serial) = split /,/, @$hcp[0];
my $id = "";
my $prof = "";
my $ips = "";
my $bpa = "";
my $side = "";
push @values, join( ",",
$hwtype,$server,$id,$model,$serial,$side,$server,$prof,$bpa,$ips );
}
#########################################
# Save hardware connections
#########################################
$filter = "type_model_serial_num,ipaddr,sp,side";
my $conns = xCAT::PPCcli::lssysconn( $exp, "alls", $filter );
$Rc = shift(@$conns);
#########################################
# Return error
#########################################
if ( $Rc != SUCCESS ) {
return( @$conns[0] );
}
foreach my $con ( @$conns ) {
my ($mtms,$ipaddr,$sp,$side) = split /,/,$con;
my $value = undef;
if ( $sp =~ /^primary$/ or $side =~ /^a$/ ) {
$value = "A";
} elsif ($sp =~ /^secondary$/ or $side =~ /^b$/ ) {
$value = "B";
}
$hwconn{$ipaddr} = "$mtms,$value";
}
#########################################
# Enumerate frames (IVM has no frame)
#########################################
if ( $hwtype ne "ivm" ) {
$filter = "type_model,serial_num,name,frame_num,ipaddr_a,ipaddr_b";
my $frames = xCAT::PPCcli::lssyscfg( $exp, "bpas", $filter );
$Rc = shift(@$frames);
#####################################
# Expect error
#####################################
if ( $Rc == EXPECT_ERROR ) {
return( @$frames[0] );
}
#####################################
# CLI error
#####################################
if ( $Rc == RC_ERROR ) {
return( @$frames[0] );
}
#####################################
# If frames found, enumerate cages
#####################################
if ( $Rc != NR_ERROR ) {
$filter = "cage_num,type_model_serial_num";
foreach my $val ( @$frames ) {
my ($model,$serial) = split /,/, $val;
my $mtms = "$model*$serial";
my $cages = xCAT::PPCcli::lssyscfg($exp,"cage",$mtms,$filter);
$Rc = shift(@$cages);
#############################
# Skip...
# Frame in bad state
#############################
if ( $Rc != SUCCESS ) {
push @values, "# $mtms: ERROR @$cages[0]";
next;
}
#############################
# Success
#############################
foreach ( @$cages ) {
my ($cageid,$mtms) = split /,/;
$cage{$mtms} = "$cageid,$val";
}
}
}
}
#########################################
# Enumerate CECs
#########################################
$filter = "name,type_model,serial_num,ipaddr";
my $cecs = xCAT::PPCcli::lssyscfg( $exp, "fsps", $filter );
$Rc = shift(@$cecs);
#########################################
# Return error
#########################################
if ( $Rc != SUCCESS ) {
return( @$cecs[0] );
}
foreach ( @$cecs ) {
#####################################
# Get CEC information
#####################################
my ($fsp,$model,$serial,$ips) = split /,/;
my $mtms = "$model*$serial";
my $cageid = "";
my $fname = "";
#####################################
# Get cage CEC is in
#####################################
my $frame = $cage{$mtms};
#####################################
# Save frame information
#####################################
if ( defined($frame) ) {
my ($cage,$model,$serial,$name,$id,$ipa,$ipb) = split /,/, $frame;
my $prof = "";
my $bpa = "";
$cageid = $cage;
$fname = $name;
#######################################
# Convert IP-A to short-hostname.
# If fails, use user-defined FSP name
#######################################
my $host = getshorthost( $ipa );
if ( defined($host) ) {
$fname = $host;
}
#######################################
# Save two sides of BPA seperately
#######################################
#my $bpastr = join( ",","bpa",$fname,$id,$model,$serial,"A",$server,$prof,$bpa,$ipa);
#if ( !grep /^\Q$bpastr\E$/, @values)
#{
# push @values, join( ",",
# "bpa",$fname,$id,$model,$serial,"A",$server,$prof,$bpa,$ipa);
#}
#$bpastr = join( ",","bpa",$fname,$id,$model,$serial,"B",$server,$prof,$bpa,$ipb);
#if ( !grep /^\Q$bpastr\E$/, @values)
#{
# push @values, join( ",",
# "bpa",$fname,$id,$model,$serial,"B",$server,$prof,$bpa,$ipb);
#}
push @values, join( ",",
"frame",$fname,$id,$model,$serial,"",$server,$prof,$bpa,"");
}
#####################################
# Save CEC information
#####################################
my $prof = "";
#######################################
# Convert IP to short-hostname.
# If fails, use user-defined FSP name
#######################################
my $host = getshorthost( $ips );
if ( defined($host) ) {
$fsp = $host;
}
my $mtmss = $hwconn{$ips};
my ($mtms,$side) = split /,/, $mtmss;
push @values, join( ",",
"cec",$fsp,$cageid,$model,$serial,"",$server,$prof,$fname,"" );
#####################################
# Enumerate LPARs
#####################################
$filter = "name,lpar_id,default_profile,curr_profile";
my $lpars = xCAT::PPCcli::lssyscfg( $exp, "lpar", $mtms, $filter );
$Rc = shift(@$lpars);
####################################
# Expect error
####################################
if ( $Rc == EXPECT_ERROR ) {
return( @$lpars[0] );
}
####################################
# Skip...
# CEC could be "Incomplete" state
####################################
if ( $Rc == RC_ERROR ) {
push @values, "# $mtms: ERROR @$lpars[0]";
next;
}
####################################
# No results found
####################################
if ( $Rc == NR_ERROR ) {
next;
}
foreach ( @$lpars ) {
my ($name,$lparid,$dprof,$curprof) = split /,/;
my $prof = (length($curprof) && ($curprof !~ /^none$/)) ? $curprof : $dprof;
my $ips = "";
my $port = "";
#####################################
# Save LPAR information
#####################################
push @values, join( ",",
"lpar",$name,$lparid,$model,$serial,$port,$server,$prof,$fsp,$ips );
}
}
return( \@values );
}
##########################################################################
# Format responses
##########################################################################
sub format_output {
my $request = shift;
my $exp = shift;
my $values = shift;
my $opt = $request->{opt};
my %output = ();
my $hwtype = @$exp[2];
my $max_length = 0;
my $result;
###########################################
# -w flag for write to xCat database
###########################################
if ( exists( $opt->{w} )) {
my $server = @$exp[3];
my $uid = @$exp[4];
my $pw = @$exp[5];
#######################################
# Strip errors for results
#######################################
my @val = grep( !/^#.*: ERROR /, @$values );
xCAT::PPCdb::add_ppc( $hwtype, \@val );
}
###########################################
# -u flag for write to xCat database
###########################################
if ( exists( $opt->{u} )) {
#######################################
# Strip errors for results
#######################################
my @val = grep( !/^#.*: ERROR /, @$values );
$values = xCAT::PPCdb::update_ppc( $hwtype, \@val );
if ( exists( $opt->{x} ) or exists( $opt->{z} ))
{
unshift @$values, "hmc";
}
}
###########################################
# -x flag for xml format
###########################################
if ( exists( $opt->{x} )) {
$result .= format_xml( $hwtype, $values );
}
###########################################
# -z flag for stanza format
###########################################
elsif ( exists( $opt->{z} )) {
$result .= format_stanza( $hwtype, $values );
}
else {
$result = sprintf( "#Updated following nodes:\n") if ( exists( $opt->{u}));
#######################################
# Get longest name for formatting
#######################################
my $nodehash;
my @errmsg;
foreach ( @$values ) {
##############################################
# Skip error message after saving it for last
##############################################
if ( /^#.*: ERROR / ) {
push @errmsg, $_;
next;
}
/([^\,]+),([^\,]+),/;
$nodehash->{$1.$2} = $_;
my $length = length( $2 );
$max_length = ($length > $max_length) ? $length : $max_length;
}
my $format = sprintf( "%%-%ds", ($max_length + 2 ));
$header[1][1] = $format;
#######################################
# Add header
#######################################
foreach ( @header ) {
$result .= sprintf( @$_[1], @$_[0] );
}
#######################################
# Add node information
#######################################
foreach ( sort keys %$nodehash ) {
my @data = split /,/, $nodehash->{$_};
my $i = 0;
foreach ( @header ) {
my $d = $data[$i++];
###############################
# Use IPs instead of
# hardware control address
###############################
if ( @$_[0] eq "address" ) {
if ( $data[0] !~ /^(hmc|ivm)$/ ) {
$d = $data[8];
}
}
$result .= sprintf( @$_[1], $d );
}
}
#######################################
# Add any error messages
#######################################
foreach ( @errmsg ) {
$result.= "\n$_";
}
}
$output{data} = [$result];
return( [\%output] );
}
##########################################################################
# Stanza formatting
##########################################################################
sub format_stanza {
my $hwtype = shift;
my $values = shift;
my $result;
my $nodehash;
#####################################
# Skip hardware control point
#####################################
shift(@$values);
foreach ( @$values ) {
###################################
# Skip error message
###################################
if ( /^#.*: ERROR / ) {
next;
}
/[^\,]+,([^\,]+),/;
$nodehash->{$1} = $_;
}
foreach ( sort keys %$nodehash ) {
my @data = split /,/, $nodehash->{$_};
my $type = $data[0];
my $i = 0;
#################################
# Node attributes
#################################
$result .= "$data[1]:\n\tobjtype=node\n";
#################################
# Add each attribute
#################################
foreach ( @attribs ) {
my $d = $data[$i++];
if ( /^node$/ ) {
next;
} elsif ( /^nodetype$/ ) {
$d = $type;
} elsif ( /^groups$/ ) {
$d = "$type,all";
} elsif ( /^mgt$/ ) {
$d = $hwtype;
} elsif ( /^cons$/ ) {
if ( $type eq "lpar" ) {
$d = $hwtype;
} else {
$d = undef;
}
} elsif ( /^(mtm|serial)$/ ) {
if ( $type eq "lpar" ) {
$d = undef;
}
}
$result .= "\t$_=$d\n";
}
}
return( $result );
}
##########################################################################
# XML formatting
##########################################################################
sub format_xml {
my $hwtype = shift;
my $values = shift;
my $xml;
my $nodehash;
#####################################
# Skip hardware control point
#####################################
shift(@$values);
foreach ( @$values ) {
###################################
# Skip error message
###################################
if ( /^#.*: ERROR / ) {
next;
}
/[^\,]+,([^\,]+),/;
$nodehash->{$1} = $_;
}
#####################################
# Create XML formatted attributes
#####################################
foreach ( sort keys %$nodehash ) {
my @data = split /,/, $nodehash->{$_};
my $type = $data[0];
my $i = 0;
#################################
# Initialize hash reference
#################################
my $href = {
Node => { }
};
#################################
# Add each attribute
#################################
foreach ( @attribs ) {
my $d = $data[$i++];
if ( /^nodetype$/ ) {
$d = $nodetype{$d};
} elsif ( /^groups$/ ) {
$d = "$type,all";
} elsif ( /^mgt$/ ) {
$d = $hwtype;
} elsif ( /^cons$/ ) {
if ( $type eq "lpar" ) {
$d = $hwtype;
} else {
$d = undef;
}
} elsif ( /^(mtm|serial)$/ ) {
if ( $type eq "lpar" ) {
$d = undef;
}
}
$href->{Node}->{$_} = $d;
}
#################################
# XML encoding
#################################
$xml.= XMLout($href,
NoAttr => 1,
KeyAttr => [],
RootName => undef );
}
return( $xml );
}
##########################################################################
# Returns I/O bus information
##########################################################################
sub rscan {
my $request = shift;
my $dummy = shift;
my $exp = shift;
my $args = $request->{arg};
my $server = @$exp[3];
###################################
# Enumerate all the hardware
###################################
my $values = enumerate( $exp );
if ( ref($values) ne 'ARRAY' ) {
return( [[$server,$values,1]] );
}
###################################
# Success
###################################
my $result = format_output( $request, $exp, $values );
unshift @$result, "FORMATDATA6sK4ci";
return( $result );
}
1;