diff --git a/perl-xCAT/xCAT/FSPflash.pm b/perl-xCAT/xCAT/FSPflash.pm new file mode 100644 index 000000000..08705ef46 --- /dev/null +++ b/perl-xCAT/xCAT/FSPflash.pm @@ -0,0 +1,648 @@ +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html + +package xCAT::FSPflash; +use strict; +use Getopt::Long; +use xCAT::PPCcli qw(SUCCESS EXPECT_ERROR RC_ERROR NR_ERROR); +use xCAT::Usage; +use xCAT::PPCinv; +use xCAT::DSHCLI; +use xCAT::Table; +use Getopt::Long; +use File::Spec; +use xCAT::PPCrflash; +use Data::Dumper; +use xCAT::Utils; +use xCAT::FSPinv; +use POSIX "WNOHANG"; +use Storable qw(freeze thaw); +use Thread qw(yield); + +my $packages_dir= (); +my $activate = (); +my $verbose = 0; +$::POWER_DEST_DIR = "/tmp"; +my $release_level; +my $active_level; +my @dirlist; + +####################################### +# This flag tracks the operation to be performed. If set, it means we need +# to commit a previously applied update or else recover from one. +####################################### +my $housekeeping = undef; + +##################################### +#For -V|--verbose,put the $msg into @value +################################### +sub dpush { + my $value = shift; + my $msg = shift; + + if($verbose == 1) { + push(@$value,$msg); + } +} + +########################################################################## +# Parse the command line for options and operands +########################################################################## +sub parse_args { + xCAT::PPCrflash::parse_args(@_); +} + +########################################################################## +# Invokes the callback with the specified message +########################################################################## +sub send_msg { + + my $request = shift; + my $ecode = shift; + my %output; + + ################################################# + # Called from child process - send to parent + ################################################# + if ( exists( $request->{pipe} )) { + my $out = $request->{pipe}; + + $output{errorcode} = $ecode; + $output{data} = \@_; + print $out freeze( [\%output] ); + print $out "\nENDOFFREEZE6sK4ci\n"; + } + ################################################# + # Called from parent - invoke callback directly + ################################################# + elsif ( exists( $request->{callback} )) { + my $callback = $request->{callback}; + + $output{errorcode} = $ecode; + $output{data} = \@_; + $callback->( \%output ); + } +} + + +#-------------------------------------------------------------------------# +# get_lic_filenames - construct and validate the lup filenames for each # +# each node # +#-------------------------------------------------------------------------# +# +sub get_lic_filenames { + my $mtms = shift; + my $upgrade_required = 0; + my $msg = undef; + my $filename; + + if(! -d $packages_dir) { + $msg = "The directory $packages_dir doesn't exist!"; + return ("","","", $msg, -1); + } + + #print "opening directory and reading names\n"; + opendir DIRHANDLE, $packages_dir; + @dirlist= readdir DIRHANDLE; + closedir DIRHANDLE; + + @dirlist = File::Spec->no_upwards( @dirlist ); + + # Make sure we have some files to process + # + if( !scalar( @dirlist ) ) { + $msg = "directory $packages_dir is empty"; + return ("","","",$msg, -1); + } + + $release_level =~/(\w{4})(\d{3})/; + my $pns = $1; + my $fff = $2; + + #Find the latest version lic file + @dirlist = grep /\.rpm$/, @dirlist; + @dirlist = grep /$1/, @dirlist; + if( !scalar( @dirlist ) ) { + $msg = "There isn't a package suitable for $mtms"; + return ("","","",$msg, -1); + } + if( scalar(@dirlist) > 1) { + # Need to find the latest version package. + @dirlist =reverse sort(@dirlist); + my $t = "\n"; + foreach $t(@dirlist) { + $msg =$msg."$t\t"; + } + } + + $filename = File::Spec->catfile( $packages_dir, $dirlist[0] ); + $dirlist[0] =~ /(\w{4})(\d{3})_(\w{3})_(\d{3}).rpm$/; + ############## + #If the release levels are different, it will be upgrade_required. + ############# + if($fff ne $2) { + $upgrade_required = 1; + } else { + + if(($pns eq $1) && ($4 <= $active_level)) { + $msg = $msg. "Upgrade $mtms $activate!"; + # if($activate ne "concurrent") { + # $msg = "Option --actviate's value should be disruptive"; + # return ("", "","", $msg, -1); + # } + } else { + $msg = $msg . "Upgrade $mtms disruptively!"; + if($activate ne "disruptive") { + $msg = "Option --activate's value shouldn't be concurrent, and it must be disruptive"; + return ("", "","", $msg, -1); + } + } + } + #print "filename is $filename\n"; + my $xml_file_name = $filename; + $xml_file_name =~ s/(.+\.)rpm/\1xml/; + #print "check_licdd_update: source xml file is $xml_file_name\n"; + + if( ( -z $filename)|| ( -z $xml_file_name) ) { + $msg = "The package $filename or xml $xml_file_name is empty" ; + return ("", "", "", $msg, -1); + } + + return ($filename, $xml_file_name ,$upgrade_required, $msg, 0); + +} + + +sub get_one_mtms { + my $exp = shift; + my $bpa = shift; + my $cmd = "lssyscfg -r cage -e $bpa"; + my $mtms; + my $msg; + + my $values = xCAT::PPCcli::send_cmd( $exp, $cmd ); + my $Rc = shift(@$values); + + ##################################### + # Return error + ##################################### + if ( $Rc != SUCCESS ) { + $msg = "ERROR: Failed to find a CEC managed by $bpa on the HMC"; + return ("", $msg); + } + + foreach (@$values) { + if( $_ =~ /cage_num=(\w*),contents=sys,type_model_serial_num=(\w+)-(\w+)\*(\w+),loc_code=(\w+).(\w+).(\w+)/) { + $mtms = "$2-$3*$4"; + last; + } + } + + + #print "the managed system is $mtms!\n"; + return ($mtms, $msg); +} + +sub process_node { + my $req = shift; + my $node = shift; + + my $tab = xCAT::Table->new("vpd"); + my $msg; + unless ($tab) { + $msg = "ERROR: Unable to open basic ppc table for configuration"; + return ("", $msg); + } + + print "in process_node1, node $node\n"; + print Dumper($node); + my $ent = $tab->getNodeAttribs($node, ['serial', 'mtm']); + print "in process_node\n"; + print Dumper($ent); + + my $serial = $ent->{'serial'}; + my $mtm = $ent->{'mtm'}; + ################################# + #Get node + ################################# + print "in get_related_fsp_bpa(), serial = $serial, mtm= $mtm\n"; + my @ents = $tab->getAllAttribsWhere("serial=\"$serial\" and mtm=\"$mtm\"", 'node'); + if (@ents < 0) { + $msg = "failed to get the FSPs or BPAs whose mtm is $mtm, serial is $serial!"; + return ("", $msg); + } + my $e; + print Dumper(@ents); + foreach $e (@ents) { + if($e->{node} ne $node) { +# push @{$req->{node}},$e->{node}; + push @{$req->{noderange}},$e->{node}; + } + } +} + +sub get_related_fsp_bpa { + my $mtm = shift; + my $serial = shift; + my $tab = xCAT::Table->new("vpd"); + my $msg; + unless ($tab) { + $msg = "ERROR: Unable to open basic ppc table for configuration"; + return ("", $msg); + } + ################################# + #Get node + ################################# + print "in get_related_fsp_bpa(), serial = $serial, mtm= $mtm\n"; + my @ent = $tab->getAllAttribsWhere("serial=\"$serial\" and mtm=\"$mtm\"", 'node'); + if (@ent < 0) { + $msg = "failed to get the FSPs or BPAs whose mtm is $mtm, serial is $serial!"; + return ("", $msg); + } + return(\@ent); + +} + +sub get_hcp_id { + my $node = shift; + + my $tab = xCAT::Table->new("ppc"); + my $msg; + unless ($tab) { + $msg = "ERROR: Unable to open basic ppc table for configuration"; + return ("", $msg); + } + ################################# + #Get node + ################################# + my @ent = $tab->getNodeAttribs($node, ['hcp', 'id']); + if (@ent < 0) { + $msg = "failed to get the hcp and id of $node!"; + return ("", $msg); + } + return($ent[0]->{hcp}, $ent[0]->{id}); + +} + + + + + +########################################################################## +# Forks a process to run the action command +########################################################################## +sub fork_cmd { + + my $node_name = shift; + my $attrs = shift; + my $action = shift; + my $pipe ; + + ####################################### + # Pipe childs output back to parent + ####################################### + my $parent; + my $child; + pipe $parent, $child; + my $pid = xCAT::Utils->xfork; + my $res; + + if ( !defined($pid) ) { + ################################### + # Fork error + ################################### + print "Fork error:!"; + return undef; + } + elsif ( $pid == 0 ) { + ################################### + # Child process + ################################### + close( $parent ); + $pipe = $child; + + $res = action( $node_name, $attrs, $action ); + print "res\n"; + print Dumper($res); + my %output; + $output{node} = $node_name; + $output{ret} = @$res[2]; + $output{contents} = @$res[1]; +# print $pipe %output; +# print $pipe freeze(\%output); + my @outhash; + push @outhash,\%output; + print $pipe freeze([@outhash]); +# print $pipe "good"; + print $pipe "\nENDOFFREEZE6sK4ci\n"; + exit(0); + } + else { + ################################### + # Parent process + ################################### + close( $child ); + return( $parent, $pid ); + } + return(0); +} + + + + +sub action { + my $node_name = shift; + my $attrs = shift; + my $action = shift; +# my $user = "HMC"; +# my $password = "abc123"; + my $fsp_api ="/home/fsp-api"; + my $id = 1; + my $fsp_name = (); + my $fsp_ip = (); + my $target_list=(); + my $type = (); # fsp|lpar -- 0. BPA -- 1 + my @result; + my $Rc = 0 ; + my %outhash = (); + my $res; + + $id = $$attrs[0]; + $fsp_name = $$attrs[3]; + + my %objhash = (); + $objhash{$fsp_name} = "node"; + my %myhash = xCAT::DBobjUtils->getobjdefs(\%objhash); + my $password = $myhash{$fsp_name}{"passwd.hscroot"}; + print "fspname:$fsp_name password:$password\n"; + print Dumper(%myhash); + if(!$password ) { + $res = "The password.hscroot of $fsp_name in ppcdirect table is empty"; + return ([$node_name, $res, -1]); + } + # my $user = "HMC"; + my $user = "hscroot"; +# my $cred = $request->{$fsp_name}{cred}; +# my $user = @$cred[0]; +# my $password = @$cred[1]; + + if($action =~ /^commit$/) { $action = "code_commit"} + if($action =~ /^recover$/) { $action = "code_reject"} + if($action =~ /^disruptive$/) { $action = "code_update"} + if($action =~ /^concurrent$/) { + $res = "\'$action\' option not supported in FSPflash.Please use disruptive mode"; + return ([$node_name, $res, -1]); + } + + + if($$attrs[4] =~ /^fsp$/) { + $type = 0; + $id = 0; + } else { + $type = 1; + } + + ############################ + # Get IP address + ############################ + $fsp_ip = xCAT::Utils::get_hdwr_ip($fsp_name); + if($fsp_ip == -1) { + $res = "Failed to get the $fsp_name\'s ip"; + return ([$node_name, $res, -1]); + } + + print "fsp name: $fsp_name\n"; + print "fsp ip: $fsp_ip\n"; + + my $cmd = "$fsp_api -a $action -u $user -p $password -t $type:$fsp_ip:$id:$node_name: -d /install/packages_fw/"; + + print "cmd: $cmd\n"; + $SIG{CHLD} = (); + my $res = xCAT::Utils->runcmd($cmd, -1); + #my $res = "good"; + $Rc = $::RUNCMD_RC; + #$Rc = -1; + ################## + # output the prompt + ################# + #$outhash{ $node_name } = $res; + + return( [$node_name,$res, $Rc] ); + +} + + + + +########################## +#Performs Licensed Internal Code (LIC) update support for HMC-attached POWER5 and POWER6 Systems +########################### +sub rflash { + + my $request = shift; + my $hash = shift; + my $exp = shift; + my $subreq = $request->{subreq}; + my $hwtype = @$exp[2]; + my @result; + my $timeout = $request->{ppctimeout}; + my $housekeeping = $request->{housekeeping}; + $packages_dir = $request->{opt}->{p}; + $activate = $request->{opt}->{activate}; + + my $mtms; + my $h; + my $user; + + my $tmp_file; #the file handle of the stanza + my $rpm_file; + my $xml_file; + my @rpm_files; + my @xml_files; + my $upgrade_required; + my $stanza = undef; + my $mtms_t; + my @value; + my %infor; + my $role ; #0x01: BPC A, BPC B; 0x01: Primary or only FSP, 0x02: Backup FSP + + print "in Directflash \n"; + print Dumper($request); + print Dumper($hash); + + #################################### + # Power commands are grouped by hardware control point + # In Direct attach support, the hcp is the related fsp. + #################################### + + # Example of $hash. + #VAR1 = { + # '9110-51A*1075ECF' => { + # 'Server-9110-51A-SN1075ECF' => [ + # 0, + # 0, + # '9110-51A*1075ECF', + # 'Server-9110-51A-SN1075ECF', + # 'fsp', + # 0 + # ] + # } + # }; + my $flag = 0; + my $flag2 = 0; + while (my ($mtms,$h) = each(%$hash) ) { + # + #For one mtms, it just needs to do the operation one time. + # + $flag += 1; + if($flag > 1) { + last; + } + + $mtms =~ /(\w+)-(\w+)\*(\w+)/; + my $mtm = "$1-$2"; + my $serial = $3; + + + while (my ($name,$d) = each(%$h) ) { + $flag2 += 1; + if($flag2 > 1) { + last; + } + my $values = xCAT::FSPinv::action( $name, $d, "list_firmware_level"); + # my $level = xCAT::PPCcli::lslic( $exp, $d, $timeout ); + my $Rc = shift(@$values); + my $level = $$values[0]->{$name}; + ##################################### + # Return error + ##################################### + if ( $Rc != SUCCESS ) { + push @value, [$name,$level,$Rc]; + next; + } + + if (( $level =~ /curr_level_primary/ ) || ( $level =~ /curr_level_a/ )) { + $role = 0x01; + } else { + $role = 0x02; + } + + if ( $level =~ /ecnumber=(\w+)/ ) { + $release_level = $1; + &dpush( \@value, [$name,"$mtms :release level:$1"]); + } + + if ( $level =~ /activated_level=(\w+)/ ) { + $active_level = $1; + &dpush( \@value, [$name,"$mtms :activated level:$1"]); + } + + my $msg; + if(!defined($housekeeping)) { + my $flag = 0; + ($rpm_file, $xml_file, $upgrade_required,$msg, $flag) = &get_lic_filenames($mtms); + if( $flag == -1) { + push (@value, [$name,"$mtms: $msg"]); + push (@value, [$name,"Failed to upgrade the firmware of $name"]); + return (\@value); + } + dpush ( \@value, [$name, $msg]); + } + my $nodes = get_related_fsp_bpa( $mtm, $serial); + print Dumper($nodes); + my $i = 0; + my $flag = 0; + my $c = @$nodes; + my $name2 = undef; + if ($c == 1 && $role == 0x01 ) { + + } + if ($c == 1 && $role == 0x02 ) { + + push(@result,[$name, "$name\'s role is Backup FSP or BPC side B). Please configure the Primary FSP or BPC side A.", -1]); + } + if($c == 2 && $role == 0x01 ) { + if($$nodes[0]->{node} eq $name) { + $i = 0; + $name2 = $$nodes[1]->{node}; #Secondary FSP or BPC side B. + } else { + $name2 = $name; #Secondary FSP or BPC side B. + $name = $$nodes[1]->{node}; #the Primary FSP or BPC side A. + } + } + + if($c ==2 && $role == 0x02) { + if($$nodes[0]->{node} eq $name) { + $name2 = $name; # Secondary FSP or BPC side B. + $name = $$nodes[1]->{node};#the Primary FSP or BPC side A. + } else { + $name2 = $$nodes[1]->{node}; #Secondary FSP or BPC side B. + } + } + print "name: $name, name2: $name2\n"; + + my $children = 0; + $SIG{CHLD} = sub { while (waitpid(-1, WNOHANG) > 0) {print "child exit\n";$children--;} }; + my $fds = new IO::Select; + my $pipe; + if(defined($name2) ) { + my($hcp, $id) = get_hcp_id($name2); + my @dt = ($id, @$d[1], $mtms, $hcp, @$d[4], 0); + + if( defined( $housekeeping ) ) { + ($pipe) = fork_cmd( $name2, \@dt, $housekeeping ); + + } else { + ($pipe) = fork_cmd( $name2, \@dt, $activate); + } + if ( $pipe ) { + $fds->add( $pipe ); + $children++; + } + sleep(5); + } + $pipe = undef; + if( defined( $housekeeping ) ) { + ($pipe) = fork_cmd( $name, $d, $housekeeping ); + + } else { + ($pipe) = fork_cmd( $name, $d, $activate ); + } + if ( $pipe ) { + $fds->add( $pipe ); + $children++; + } + print "count:\n"; + print $fds->count; + print "children:$children\n"; + while ( $fds->count > 0 or $children > 0 ) { + my @ready_fds = $fds->can_read(1); + foreach my $rfh (@ready_fds) { + my $val = <$rfh>; + if( defined($val)) { + while($val !~ /ENDOFFREEZE6sK4ci/) { + $val .= <$rfh>; + } + my $resp = thaw($val); + foreach my $t( @$resp ) { + print Dumper($t); + push @result, [$t->{node}, $t->{contents}, $t->{ret}]; + } + next; + } + $fds->remove($rfh); + close($rfh); + } + } + + } + } + push(@value, @result); + return (\@value); + + + +} + +1; + + diff --git a/perl-xCAT/xCAT/FSPinv.pm b/perl-xCAT/xCAT/FSPinv.pm index 4c069ba87..836647b6d 100644 --- a/perl-xCAT/xCAT/FSPinv.pm +++ b/perl-xCAT/xCAT/FSPinv.pm @@ -94,7 +94,7 @@ sub firmware { # Return error ##################################### if ( $Rc != SUCCESS ) { - push @result, [$name,@$values[0],$Rc]; + push @result, [$name,$data->{$name},$Rc]; next; } diff --git a/perl-xCAT/xCAT/PPCrflash.pm b/perl-xCAT/xCAT/PPCrflash.pm index ead161da6..3284bfffe 100644 --- a/perl-xCAT/xCAT/PPCrflash.pm +++ b/perl-xCAT/xCAT/PPCrflash.pm @@ -11,7 +11,7 @@ use xCAT::Table; use Getopt::Long; use File::Spec; use POSIX qw(tmpnam); -use xCAT::FSPflash.pm; +use xCAT::FSPflash; my $packages_dir= ();