#!/usr/bin/env perl # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html package xCAT::FSPUtils; BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } # if AIX - make sure we include perl 5.8.2 in INC path. # Needed to find perl dependencies shipped in deps tarball. if ($^O =~ /^aix/i) { unshift(@INC, qw(/usr/opt/perl5/lib/5.8.2/aix-thread-multi /usr/opt/perl5/lib/5.8.2 /usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi /usr/opt/perl5/lib/site_perl/5.8.2)); } use lib "$::XCATROOT/lib/perl"; require xCAT::Table; use POSIX qw(ceil); use File::Path; use strict; use Symbol; require xCAT::InstUtils; require xCAT::NetworkUtils; require xCAT::Schema; require xCAT::Utils; require xCAT::TableUtils; #use Data::Dumper; require xCAT::NodeRange; use xCAT::MsgUtils qw(verbose_message); #------------------------------------------------------------------------------- =head3 getHcpAttribs Description: Build 2 Hashes from ppc/vpd table one hash is : CEC/Frame is the Key, FSPs/BPAs are the value. the other is: fsp/bpa is the key, the side is the value. Arguments: $request: this hash will be usded to store the ppc hash and vpd hash $tabs: the hash store the new tables for ppc and bpd. Returns: Globals: none Error: none Example: xCAT::FSPUtils::getPPCAttribs($request, \%tabs); =cut #------------------------------------------------------------------------------- sub getHcpAttribs { my $request = shift; my $tabs = shift; my %ppchash ; my %vpd ; my @vs = $tabs->{vpd}->getAllNodeAttribs(['node', 'side']); for my $entry ( @vs ) { my $tmp_node = $entry->{node}; my $tmp_side = $entry->{side}; if(defined($tmp_node) && defined($tmp_side)) { $vpd{$tmp_node} = $tmp_side ; } } my @ps = $tabs->{ppc}->getAllNodeAttribs(['node','parent','nodetype','hcp']); for my $entry ( @ps ) { my $tmp_parent = $entry->{parent}; my $tmp_node = $entry->{node}; my $tmp_type = $entry->{nodetype}; if(defined($tmp_node) && defined($tmp_type) && ($tmp_type =~ /^(fsp|bpa)$/ && $tmp_parent) ) { push @{$ppchash{$tmp_parent}{children}}, $tmp_node; #push @{$ppchash{$tmp_parent}}, $tmp_node; } if (defined($tmp_node) && defiend($tmp_type) && ($tmp_type eq "blade") && defined($entry->{hcp})) { push @{$ppchash{$tmp_node}{children}}, $entry->{hcp}; } #if(exists($ppchash{$tmp_node})) { # if( defined($tmp_type) ) { # #push @{$ppchash{$tmp_node}{type}}, $tmp_type; # } else { # my %output; # my $msg = "no type for $tmp_type in the ppc table."; # $output{errorcode} = 1; # $output{data} = $msg; # $request->{callback}->( \%output ); # } #} } $request->{ppc}=\%ppchash ; $request->{vpd}=\%vpd ; } #------------------------------------------------------------------------------- =head3 getIPaddress Description: Used by DFM related functions. When getting the IPs for CECs' FSPs, or getting the IPs for Frames' BPAs. And the IPs order is A-0,A-1,B-0,B-1. When getting the IP for one FSP or one BPA, if the $nodetocheck it one IP, it will return the IP immediately; if not, it will get the IP of the FSP or BPA. Arguments: $request: Because getIPaddress() is always used for one node after the process fork. Avoiding to access the DB for each node in the subprocess, we should collect the attributs before process fork, and put the attributes in the $request variable. For the getIpaddress(). The $request parameter should include the ppc hash which mapping the CEC->FSPs and Frames->BPAs, and vpd hash the fsp->side and the bpa->side. $type: the type of the $nodetocheck $nodetocheck: Node name, only one node at a time. $port: if the $nodetocheck is a fsp or bpa, it will be usde. Returns: ip address(s) Globals: none Error: none Example: my $c1 = xCAT::FSPUtils::getIPaddress($request, $type, $nodetocheck); =cut #------------------------------------------------------------------------------- sub getIPaddress { # require xCAT::Table; my $request = shift; my $type = shift; my $nodetocheck = shift; my $port = shift; if (xCAT::NetworkUtils::isIpaddr($nodetocheck)) { return $nodetocheck; } my $side = "[A|B]"; if (!defined($port)) { $port = "[0|1]"; } my $ppc = $request->{ppc}; my $vpd = $request->{vpd}; # only need to parse IP addresses for Frame/CEC/BPA/FSP #my $type = xCAT::DBobjUtils->getnodetype($nodetocheck); #my $type = $$attrs[4]; if ($type) { my @children; my %node_side_pairs = (); my $children_num = 0; my $parent; if ($type eq "bpa" or $type eq "fsp") { push @children, $nodetocheck; #my $tmp_s = $vpdtab->getNodeAttribs($nodetocheck, ['side']); my $tmp_s = $vpd->{$nodetocheck}; if ($tmp_s and $tmp_s =~ /(A|B)-\d/i) { $side = $1; # get side for the fsp } else { return -3; } } elsif ($type eq "frame" or $type eq "cec" or ($type =~ /lpar/i)) { #In DFM #1. when the node type is frame, its hcp( $nodetocheck ) is frame, #and it will get the BPAs IPs for the Frame. #2. when the node type is CEC, its hcp( $nodetocheck ) is CEC, #and it will get the FSPs IPs for the CEC. #3. when the node type is lpar, its hcp is the CEC. #the $nodetocheck is its' hcp. So set $nodetocheck to $parent variable. #And then get the FSPs IPs for the CEC. $parent = $nodetocheck; } elsif ($type eq "blade") { return $ppc->{$nodetocheck}->{children}->[0]; } else { return undef; } if( @children == 0 ) { if( exists($ppc->{$parent} ) ) { #for cec/frame, get the FSPs/BPAs from the hash we built in getHcpAttribs() before. @children = @{$ppc->{$parent}->{children}}; } else { return undef; } } foreach my $tmp_n( @children) { my $tmp_s = $vpd->{$tmp_n}; if ($tmp_s and $tmp_s =~ /^$side-$port$/i) { $tmp_s =~ s/a/A/; $tmp_s =~ s/b/B/; if (xCAT::NetworkUtils::isIpaddr($tmp_n)) { $node_side_pairs{$tmp_s} = $tmp_n; $children_num++; } else { my $tmpip = xCAT::NetworkUtils->getipaddr($tmp_n); if (!$tmpip) { #my $hoststab = xCAT::Table->new( 'hosts' ); #my $tmp = $hoststab->getNodeAttribs($tmp_n, ['ip']); #if ($tmp->{ip}) { # $tmpip = $tmp->{ip}; #} } if ($tmpip) { $node_side_pairs{$tmp_s} = $tmpip; $children_num++; } } # end of parse IP address for a fsp/bpa } # end of parse a child's side } #end of loop for children if ($children_num == 0) { return undef; #no children or brothers for this node. } my @keys = qw(A-0 A-1 B-0 B-1); my $out_strings = undef; foreach my $tmp (@keys) { if (!$node_side_pairs{$tmp}) { $node_side_pairs{$tmp} = ''; } } $out_strings = $node_side_pairs{"A-0"}.','.$node_side_pairs{"A-1"}.','.$node_side_pairs{"B-0"}.','.$node_side_pairs{"B-1"}; return $out_strings; } else { return undef; } } #------------------------------------------------------------------------------- =head3 fsp_api_action Description: invoke the fsp_api to perform the functions Arguments: $node_name: $attrs: an attributes hash $action: the operations on the fsp, bpa or lpar $tooltype: 0 for HMC, 1 for HNM Returns: Return result of the operation Globals: none Error: none Example: my $res = xCAT::FSPUtils::fsp_api_action( $node_name, $d, "add_connection", $tooltype ); Comments: =cut #------------------------------------------------------------------------------- sub fsp_api_action { my $request = shift; my $node_name = shift; my $attrs = shift; my $action = shift; my $tooltype = shift; my $parameter = shift; # my $user = "HMC"; # my $password = "abc123"; my $fsp_api = ($::XCATROOT) ? "$::XCATROOT/sbin/fsp-api" : "/opt/xcat/sbin/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; my $user; my $password; my $fsp_bpa_type; if( !defined($tooltype) ) { $tooltype = 0; } $id = $$attrs[0]; $fsp_name = $$attrs[3]; xCAT::MsgUtils->verbose_message($request, "fsp_api_action START node:$node_name,type:$$attrs[4]."); if($$attrs[4] =~ /^fsp$/ || $$attrs[4] =~ /^lpar$/ || $$attrs[4] =~ /^cec$/) { $type = 0; $fsp_bpa_type="fsp"; } elsif($$attrs[4] =~ /^bpa$/ || $$attrs[4] =~ /^frame$/) { $type = 1; $fsp_bpa_type="bpa"; } elsif($$attrs[4] =~ /^blade$/) { $type = 0; $fsp_bpa_type = "blade"; } else { $res = "$fsp_name\'s type is $$attrs[4]. Not support for $$attrs[4]"; return ([$node_name, $res, -1]); } if( $action =~ /^add_connection$/) { ############################ # Get IP address ############################ $fsp_ip = getIPaddress($request, $$attrs[4], $fsp_name, $parameter ); undef($parameter); } else { $fsp_ip = getIPaddress($request, $$attrs[4], $fsp_name ); } xCAT::MsgUtils->verbose_message($request, "fsp_api_action getIPaddress:$fsp_ip."); if(!defined($fsp_ip)) { $res = "Failed to get IP address for $fsp_name or the related FSPs/BPAs."; return ([$node_name, $res, -1]); } if($fsp_ip eq "-1") { $res = "Cannot open vpd table"; return ([$node_name, $res, -1]); } elsif( $fsp_ip eq "-3") { $res = "It doesn't have the FSPs or BPAs whose side is the value as specified or by default."; return ([$node_name, $res, -1]); } #print "fsp name: $fsp_name\n"; #print "fsp ip: $fsp_ip\n"; #In DFM, only the add_connection action need the userid/password to create the connection #between hdwr_svr and FSPs or BPAs. if( $action =~ /^add_connection$/) { my $tmp_node; if( $$attrs[4] =~ /^cec$/ || $$attrs[4] =~ /^frame$/ ) { $tmp_node = $node_name; } elsif ($$attrs[4] =~ /^blade$/) { $tmp_node = $$attrs[5]; } else { $tmp_node = $fsp_name; } my $cred = $request->{$tmp_node}{cred}; ($user, $password) = @$cred ; #($user, $password) = xCAT::PPCdb::credentials( $tmp_node, $fsp_bpa_type,'HMC'); if ( !$password) { $res = "Cannot get password of userid 'HMC'. Please check table 'passwd' or 'ppcdirect'."; return ([$node_name, $res, -1]); } # The userid for creating connection only is "HMC". $user = 'HMC'; } my $cmd; my $install_dir = xCAT::TableUtils->getInstallDir(); if( $action =~ /^(code_update|get_compatible_version_from_rpm)$/) { $cmd = "$fsp_api -a $action -T $tooltype -t $type:$fsp_ip:$id:$node_name:$parameter -d $install_dir/packages_fw/"; } elsif($action =~ /^code_updateD$/) { $cmd = "$fsp_api -a code_update -D -T $tooltype -t $type:$fsp_ip:$id:$node_name:$parameter -d $install_dir/packages_fw/"; } elsif($action =~ /^add_connection$/) { $cmd = "$fsp_api -a $action -u $user -p $password -T $tooltype -t $type:$fsp_ip:$id:$node_name:"; } elsif ($action =~ /^set_frame_number$/) { $cmd = "$fsp_api -a $action -T $tooltype -f $parameter -t $type:$fsp_ip:$id:$node_name:"; } else { if( defined($parameter) ) { if ($action =~ /^set_(frame|cec|lpar)_name$/) { $cmd = "$fsp_api -a $action -n $parameter -T $tooltype -t $type:$fsp_ip:$id:$node_name:"; } elsif( $parameter !=0 && $action =~ /^(on|reset)$/ ) { #powerinterval for lpars power on $cmd = "$fsp_api -a $action -i $parameter -T $tooltype -t $type:$fsp_ip:$id:$node_name:"; } else { $cmd = "$fsp_api -a $action -T $tooltype -t $type:$fsp_ip:$id:$node_name:$parameter"; } } else { $cmd = "$fsp_api -a $action -T $tooltype -t $type:$fsp_ip:$id:$node_name:"; } } xCAT::MsgUtils->verbose_message($request, "fsp_api_action cmd:$cmd."); #print "cmd: $cmd\n"; $SIG{CHLD} = 'DEFAULT'; # secure passwords in verbose mode my $tmpv = $::VERBOSE; if($action =~ /^add_connection$/) { # password involved $::VERBOSE = 0; } $res = xCAT::Utils->runcmd($cmd, -1); #$res = "good"; $Rc = $::RUNCMD_RC; $::VERBOSE = $tmpv; ################## # output the prompt ################# #$outhash{ $node_name } = $res; if(defined($res)) { $res =~ s/$node_name: //g; } xCAT::MsgUtils->verbose_message($request, "fsp_api_action return:$Rc."); return( [$node_name,$res, $Rc] ); } #------------------------------------------------------------------------------- =head3 fsp_state_action Description: invoke the fsp_api to perform the functions(all_lpars_state) Arguments: $node_name: $attrs: an attributes hash $action: the operations on the fsp, bpa or lpar $tooltype: 0 for HMC, 1 for HNM Returns: Return result of the operation Globals: none Error: none Example: my $res = xCAT::FSPUtils::fsp_state_action( $cec_bpa, $type, $action, $tooltype ); Comments: =cut #------------------------------------------------------------------------------- sub fsp_state_action { my $request = shift; my $node_name = shift; my $attrs = shift; my $action = shift; my $tooltype = shift; my $fsp_api = ($::XCATROOT) ? "$::XCATROOT/sbin/fsp-api" : "/opt/xcat/sbin/fsp-api"; my $id = 0; 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; if( !defined($tooltype) ) { $tooltype = 0; } $fsp_name = $node_name; xCAT::MsgUtils->verbose_message($request, "fsp_state_action START node:$node_name,type:$$attrs[4]."); if( $$attrs[4] =~ /^(fsp|lpar|cec|blade)$/) { $type = 0; } else { $type = 1; } ############################ # Get IP address ############################ $fsp_ip = getIPaddress($request, $$attrs[4], $fsp_name ); if(!defined($fsp_ip) or ($fsp_ip == -3)) { $res[0] = "Failed to get IP address for $fsp_name or the related FSPs/BPAs."; return ([-1, $res[0]]); } xCAT::MsgUtils->verbose_message($request, "fsp_state_action getIPaddress:$fsp_ip."); #print "fsp name: $fsp_name\n"; #print "fsp ip: $fsp_ip\n"; my $cmd; #$cmd = "$fsp_api -a $action -u $user -p $password -T $tooltype -t $type:$fsp_ip:$id:$node_name:"; $cmd = "$fsp_api -a $action -T $tooltype -t $type:$fsp_ip:$id:$node_name:"; xCAT::MsgUtils->verbose_message($request, "fsp_state_action cmd:$cmd."); #print "cmd: $cmd\n"; $SIG{CHLD} = 'DEFAULT'; @res = xCAT::Utils->runcmd($cmd, -1); #$res = "good"; $Rc = $::RUNCMD_RC; #$Rc = -1; ################## # output the prompt ################# #$outhash{ $node_name } = $res; if( @res ) { $res[0] =~ s/$node_name: //g; } xCAT::MsgUtils->verbose_message($request, "fsp_state_action return:$Rc."); return( [$Rc,@res] ); } #------------------------------------------------------------------------------- =head3 fsp_api_create_partition Description: invoke the fsp_api to perform the functions Arguments: $node_name: $attrs: an attributes hash $action: the operations on the fsp, bpa or lpar $tooltype: 0 for HMC, 1 for HNM Returns: Return result of the operation Globals: none Error: none Example: my $res = xCAT::FSPUtils::fsp_api_create_partition($request, ... ); Comments: =cut #------------------------------------------------------------------------------- sub fsp_api_create_partition { my $request = shift; my $starting_lpar_id = shift; my $octant_cfg = shift; my $node_number = shift; my $attrs = shift; my $action = shift; my $tooltype = shift; # my $user = "HMC"; # my $password = "abc123"; my $fsp_api = ($::XCATROOT) ? "$::XCATROOT/sbin/fsp-api" : "/opt/xcat/sbin/fsp-api"; my $id = 0; 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; my $number_of_lpars_per_octant; my $octant_num_needed; my $starting_octant_id; my $octant_conf_value; my $octant_cfg_value = $octant_cfg->{octant_cfg_value}; my $new_pending_interleave_mode = $octant_cfg->{memory_interleave}; if( !defined($tooltype) ) { $tooltype = 0; } #use Data::Dumper; #print Dumper($attrs); $fsp_name = $$attrs[3]; $type = 0; ############################ # Get IP address ############################ $fsp_ip = getIPaddress($request, $$attrs[4], $fsp_name ); if(!defined($fsp_ip) or ($fsp_ip == -3)) { $res = "Failed to get IP address for $fsp_name."; return ([$fsp_name, $res, -1]); } #print "fsp name: $fsp_name\n"; #print "fsp ip: $fsp_ip\n"; $starting_octant_id = int($starting_lpar_id/4); my $lparnum_from_octant = 0; my $new_pending_pump_mode = $octant_cfg->{pendingpumpmode}; my $parameters; #my $parameters = "$new_pending_pump_mode:$octant_num_needed"; my $octant_id = $starting_octant_id ; my $i = 0; for($i=$starting_octant_id; $i < (keys %$octant_cfg_value) ; $i++) { if(! exists($octant_cfg_value->{$i})) { $res = "starting LPAR id is $starting_lpar_id, starting octant id is $starting_octant_id, octant configuration value isn't provided. Wrong plan."; return ([$fsp_name, $res, -1]); } my $octant_conf_value = $octant_cfg_value->{$i}; #octant configuration values could be 1,2,3,4,5 ; AS following: # 1 - 1 partition with all cpus and memory of the octant # 2 - 2 partitions with a 50/50 split of cpus and memory # 3 - 3 partitions with a 25/25/50 split of cpus and memory # 4 - 4 partitions with a 25/25/25/25 split of cpus and memory # 5 - 2 partitions with a 25/75 split of cpus and memory if($octant_conf_value == 1) { $number_of_lpars_per_octant = 1; } elsif($octant_conf_value == 2 ) { $number_of_lpars_per_octant = 2; } elsif($octant_conf_value == 3 ) { $number_of_lpars_per_octant = 3; } elsif($octant_conf_value == 4 ) { $number_of_lpars_per_octant = 4; } elsif($octant_conf_value == 5 ) { $number_of_lpars_per_octant = 2; } else { $res = "octant $i, configuration values: $octant_conf_value. Wrong octant configuration values!\n"; return ([$fsp_name, $res, -1]); } $lparnum_from_octant += $number_of_lpars_per_octant; $octant_num_needed++; $parameters .= ":$octant_id:$octant_conf_value:$new_pending_interleave_mode"; } $parameters = "$new_pending_pump_mode:$octant_num_needed".$parameters; if($node_number != $lparnum_from_octant ) { $res = "According to the partition split rule and the starting LPAR id, $lparnum_from_octant LPARs will be gotten. But the noderange has $node_number node. Wrong plan.\n"; return ([$fsp_name, $res, -1]); } #my $new_pending_pump_mode = 1; #my $parameters = "$new_pending_pump_mode:$octant_num_needed"; #my $octant_id = $starting_octant_id ; #my $new_pending_interleave_mode = 2; #my $i = 0; #for($i = 0; $i < $octant_num_needed; $i++ ) { # $octant_id += $i; # $parameters = $parameters.":$octant_id:$octant_conf_value:$new_pending_interleave_mode"; #} my $cmd; $cmd = "$fsp_api -a $action -T $tooltype -t $type:$fsp_ip:0:$fsp_name:$parameters"; #fsp-api -a set_octant_cfg -t 0:40.7.5.1:0:M019:1:1:7:4:2 #print "cmd: $cmd\n"; $SIG{CHLD} = 'DEFAULT'; $res = xCAT::Utils->runcmd($cmd, -1); #$res = "good"; $Rc = $::RUNCMD_RC; #$Rc = -1; ################## # output the prompt ################# #$outhash{ $node_name } = $res; if( defined($res) ) { $res =~ s/$fsp_name: //; } return( [$fsp_name,$res, $Rc] ); } 1;