# 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 = $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; } } $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;