diff --git a/xCAT-server/lib/xcat/plugins/FIP.pm b/xCAT-server/lib/xcat/plugins/FIP.pm new file mode 100644 index 000000000..c5c8ce079 --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/FIP.pm @@ -0,0 +1,483 @@ +#!/usr/bin/env perl -w +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +##################################################### +# +# xCAT plugin package to handle commands that manage the xCAT object +# definitions +# +##################################################### + +package xCAT_plugin::FIP; + +use lib ("/opt/xcat/lib/perl"); +use Data::Dumper; +use Getopt::Long; +use xCAT::MsgUtils; +use strict; + +# options can be bundled up like -vV +Getopt::Long::Configure("bundling"); +$Getopt::Long::ignorecase = 0; + + +#---------------------------------------------------------------------------- + +=head3 handled_commands + + Return a list of commands handled by this plugin + +=cut + +#----------------------------------------------------------------------------- + +sub handled_commands +{ + return { + swapnodes => "FIP" + }; +} + + +########################################################################## +# Pre-process request from xCat daemon. Send the request to the the service +# nodes of the HCPs. +########################################################################## +sub preprocess_request { + + my $req = shift; + #if ($req->{_xcatdest}) { return [$req]; } #exit if preprocessed + if ($req->{_xcatpreprocessed}->[0] == 1 ) { return [$req]; } + my $callback = shift; + my $subreq = shift; + my @requests; + + # process the command line + my $rc = &parse_args($req); + if ($rc != 0) + { + &swapnodes_usage($callback); + return -1; + } + + ##################################### + # Parse arguments + ##################################### + #my $opt = parse_args( $req, $callback); + #if ( ref($opt) eq 'ARRAY' ) + #{ + # send_msg( $req, 1, @$opt ); + # delete($req->{callback}); # if not, it will cause an error -- "Can't encode a value of type: CODE" in hierairchy. + # return(1); + #} + #delete($req->{callback}); # remove 'callback' => sub { "DUMMY" } in hierairchy. + #$req->{opt} = $opt; + + #if ( exists( $req->{opt}->{V} )) { + # $req->{verbose} = 1; + #} + my $opt = $req->{opt}; + + my $current_node = $opt->{c}; + my $fip_node = $opt->{f}; + + my @ppcattribs = ('hcp', 'id', 'pprofile', 'parent', 'supernode', 'comments', 'disable'); + my $ppctab = xCAT::Table->new( 'ppc', -create=>1, -autocommit=>0); + unless ($ppctab ) { + my $rsp->{data}->[0] = "Cannot open ppc table"; + xCAT::MsgUtils->message("E", $rsp, $callback); + return 1; + } + + + my ($current_ppc_ent) = $ppctab->getAttribs({ node=>$current_node},@ppcattribs); + my ($fip_ppc_ent) = $ppctab->getAttribs({ node=>$fip_node},@ppcattribs); + my @current_attrs; + my @fip_attrs; + if( $current_ppc_ent->{'parent'} ne $fip_ppc_ent->{'parent'} ) { + my $reqcopy = {%$req}; + push @requests, $reqcopy; + return \@requests; + } else { + + if($current_ppc_ent->{'hcp'} ne $fip_ppc_ent->{'hcp'} ) { + $callback->({data=>["The two nodes are on the same CEC, but don't have the same hcp"]}); + $req = {}; + return; + } + + # find service nodes for the HCPs + # build an individual request for each service node + my $service = "xcat"; + my @hcps=[$current_ppc_ent->{'hcp'}]; + my $sn = xCAT::Utils->get_ServiceNode(\@hcps, $service, "MN"); + + # build each request for each service node + foreach my $snkey (keys %$sn) + { + #$callback->({data=>["The service node $snkey "]}); + my $reqcopy = {%$req}; + $reqcopy->{'_xcatdest'} = $snkey; + $reqcopy->{_xcatpreprocessed}->[0] = 1; + #my $hcps1=$sn->{$snkey}; + #my @nodes=(); + #foreach (@$hcps1) { + # push @nodes, @{$hcp_hash{$_}{nodes}}; + #} + #@nodes = sort @nodes; + #my %hash = map{$_=>1} @nodes; #remove the repeated node for multiple hardware control points + #@nodes =keys %hash; + #$reqcopy->{node} = \@nodes; + #print "nodes=@nodes\n"; + push @requests, $reqcopy; + } + + } + #print Dumper(\@requests); + return \@requests; +} + + + + + +#---------------------------------------------------------------------------- + +=head3 process_request + + Check for xCAT command and call the appropriate subroutine. + + Arguments: + + Returns: + 0 - OK + 1 - error + Globals: + + Error: + + Example: + + Comments: +=cut + +#----------------------------------------------------------------------------- + +sub process_request +{ + + my $request = shift; + my $callback = shift; + + my $ret; + my $msg; + + my $command = $request->{command}->[0]; + my $args = $request->{arg}; + my $filedata = $request->{stdin}->[0]; + + # figure out which cmd and call the subroutine to process + if ($command eq "swapnodes") + { + ($ret, $msg) = &swapnodes($request, $callback, $args); + } + + my $rsp; + if ($msg) + { + $rsp->{data}->[0] = $msg; + $callback->($rsp); + } + + if ($ret > 0) { + $rsp->{errorcode}->[0] = $ret; + } +} + +#---------------------------------------------------------------------------- + +=head3 processArgs + + Process the command line. Covers all four commands. + + Also - Process any input files provided on cmd line. + + Arguments: + + Returns: + 0 - OK + 1 - just print usage + 2 - error + Globals: + + Error: + + Example: + + Comments: +=cut + +#----------------------------------------------------------------------------- + +sub parse_args +{ + my $request = shift; + my $args = $request->{arg}; + my $gotattrs = 0; + my %opt =(); + + if (defined(@{$args})) { + @ARGV = @{$args}; + } else { + return 2; + } + + if (scalar(@ARGV) <= 0) { + return 2; + } + + # parse the options - include any option from all 4 cmds + Getopt::Long::Configure("no_pass_through"); + if ( !GetOptions( \%opt, qw(h|help v|version V|verbose c=s f=s ) )) { + return 2; + } + + if ( exists( $opt{v} )) { + return( \$::VERSION ); + } + + if ( exists( $opt{h}) || $opt{help}) { + return 2; + } + + if ( (!exists( $opt{c})) ||(!exists( $opt{f})) ) { + return 2; + } + + $request->{opt} = \%opt; + + return 0; +} + +#---------------------------------------------------------------------------- + +=head3 swapnodes + + Support for the xCAT chdef command. + + Arguments: + Returns: + 0 - OK + 1 - error + Globals: + + Error: + + Example: + + Comments: + +=cut + +#----------------------------------------------------------------------------- + +sub swapnodes +{ + my $request = shift; + my $callback = shift; + my $args = shift; + + my $Rc = 0; + my $error = 0; + + my $rsp; + my $action; + my $values; + my $vals; + + + my $opt = $request->{opt}; + #print Dumper($opt); + + my $current_node = $opt->{c}; + my $fip_node = $opt->{f}; + + #check the current_node and fip_node state, they should be in Not Activated state + + + # get the ppc attributes for the two nodes + #swap + #update it + my @ppcattribs = ('hcp', 'id', 'pprofile', 'parent', 'supernode', 'comments', 'disable'); + my $ppctab = xCAT::Table->new( 'ppc', -create=>1, -autocommit=>0); + unless ($ppctab ) { + $rsp->{data}->[0] = "Cannot open ppc table"; + xCAT::MsgUtils->message("E", $rsp, $callback); + return 1; + } + + my ($current_ppc_ent) = $ppctab->getAttribs({ node=>$current_node},@ppcattribs); + my ($fip_ppc_ent) = $ppctab->getAttribs({ node=>$fip_node},@ppcattribs); + my @current_attrs; + my @fip_attrs; + my $cec; + if( $current_ppc_ent->{'parent'} eq $fip_ppc_ent->{'parent'} ) { + #the attributes of the current LPAR will be used for fsp_api_action + push @current_attrs, $current_ppc_ent->{'id'}; + push @current_attrs, "0"; + push @current_attrs, $current_ppc_ent->{'parent'}; + push @current_attrs, $current_ppc_ent->{'hcp'}; + push @current_attrs, "lpar"; + push @current_attrs, "0"; + + #the attributes of the current LPAR will be used for fsp_api_action + push @fip_attrs, $fip_ppc_ent->{'id'}; + push @fip_attrs, "0"; + push @fip_attrs, $fip_ppc_ent->{'parent'}; + push @fip_attrs, $fip_ppc_ent->{'hcp'}; + push @fip_attrs, "lpar"; + push @fip_attrs, "0"; + + #For the LPARs on the same CEC, we should swap the nodes' attributes and then assign the IO which are assigned to the current LPAR to the FIP LPAR. + $cec = $current_ppc_ent->{'parent'}; + my $type = "lpar"; + $action = "all_lpars_state"; + + my $values = xCAT::FSPUtils::fsp_state_action ($cec, $type, $action); + my $Rc = shift(@$values); + if ( $Rc != 0 ) { + $rsp->{data}->[0] = $$values[0]; + xCAT::MsgUtils->message("E", $rsp, $callback); + return -1; + } + + foreach ( @$values ) { + my ($state,$lparid) = split /,/; + if( $lparid eq $current_ppc_ent->{'id'}) { + if($state ne "Not Activated") { + $rsp->{data}->[0] = "The two LPARs in one same CEC. Please make sure the two LPARs are in Not Activated state before swapping their location information"; + xCAT::MsgUtils->message("E", $rsp, $callback); + return -1; + } + } + + if( $lparid eq $fip_ppc_ent->{'id'}) { + if($state ne "Not Activated") { + $rsp->{data}->[0] = "The two LPARs in one same CEC. Please make sure the two LPARs are in Not Activated state before swapping their location information"; + xCAT::MsgUtils->message("E", $rsp, $callback); + return -1; + } + } + } + + + } + + my %keyhash = (); + # swap the current ent and the fip ent + $keyhash{'node'} = $current_node; + $ppctab->setAttribs( \%keyhash,$fip_ppc_ent ); + + $keyhash{'node'} = $fip_node; + $ppctab->setAttribs( \%keyhash,$current_ppc_ent ); + + $ppctab->commit; + $ppctab->close(); + + #set the variables to be empty + #$current_ent = (); + #$fip_ent = (); + %keyhash =(); + + # get the nodepos attributes for the two nodes + #swap + #update it + my @nodeposattribs =('rack','u','chassis','slot','room','comments','disable'); + my $nodepostab = xCAT::Table->new( 'nodepos', -create=>1, -autocommit=>0); + unless ($nodepostab ) { + $rsp->{data}->[0] = "Cannot open nodepos table"; + xCAT::MsgUtils->message("E", $rsp, $callback); + return 1; + } + + my $current_ent = $nodepostab->getAttribs({ node=>$current_node},@nodeposattribs); + my $fip_ent = $nodepostab->getAttribs({ node=>$fip_node},@nodeposattribs); + + # swap the current ent and the fip ent + $keyhash{'node'} = $current_node; + $nodepostab->setAttribs( \%keyhash,$fip_ent ); + + $keyhash{'node'} = $fip_node; + $nodepostab->setAttribs( \%keyhash,$current_ent ); + + $nodepostab->commit; + $nodepostab->close(); + + # get the slots information from fsp, swap them, and then assign them to the others. + #.... + if( $current_ppc_ent->{'parent'} eq $fip_ppc_ent->{'parent'} ) { + + $action = "get_io_slot_info"; + $values = xCAT::FSPUtils::fsp_api_action ($cec, \@current_attrs, $action); + #$Rc = shift(@$values); + $Rc = pop(@$values); + if ( $Rc != 0 ) { + $rsp->{data}->[0] = $$values[1]; + xCAT::MsgUtils->message("E", $rsp, $callback); + return 1; + } + + $action = "set_io_slot_owner"; + my $tooltype = 0; + my @data = split(/\n/, $$values[1]); + foreach my $v (@data) { + my ($lpar_id, $busid, $location, $drc_index, $owner_type, $owner, $descr) = split(/,/, $v); + if( $lpar_id eq $current_ppc_ent->{'id'} ) { + $vals = xCAT::FSPUtils::fsp_api_action ($fip_node, \@fip_attrs, $action, $tooltype, $drc_index); + $Rc = pop(@$vals); + if ( $Rc != 0 ) { + $rsp->{data}->[0] = $$vals[1]; + xCAT::MsgUtils->message("E", $rsp, $callback); + return -1; + } + } + } + } + + return ; + + +} + +#---------------------------------------------------------------------------- + +=head3 swapnodes_usage + + Arguments: + Returns: + Globals: + + Error: + + Example: + + Comments: +=cut + +#----------------------------------------------------------------------------- + +sub swapnodes_usage +{ + my $callback = shift; + my $rsp; + $rsp->{data}->[0] = + "\nUsage: swapnodes - swap the location info in the db between 2 nodes. If swapping within a cec, it will assign the IO adapters that were assigned to the defective node to the available node\n"; + $rsp->{data}->[1] = " swapnodes [-h | --help ] \n"; + $rsp->{data}->[2] = " swapnodes -c current_node -f fip_node"; + xCAT::MsgUtils->message("I", $rsp, $callback); + return 0; +} + + + +1; +