2011-03-25 06:39:06 +00:00
#!/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 ;
2012-08-09 04:07:40 +00:00
use xCAT::Utils ;
use xCAT::TableUtils ;
use xCAT::ServiceNodeUtils ;
2011-03-25 06:39:06 +00:00
# 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 ;
}
2011-12-08 07:17:50 +00:00
my ( $ current_ppc_ent ) = $ ppctab - > getNodeAttribs ( $ current_node , @ ppcattribs ) ;
my ( $ fip_ppc_ent ) = $ ppctab - > getNodeAttribs ( $ fip_node , @ ppcattribs ) ;
2011-03-25 06:39:06 +00:00
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' } ] ;
2012-08-09 04:07:40 +00:00
my $ sn = xCAT::ServiceNodeUtils - > get_ServiceNode ( \ @ hcps , $ service , "MN" ) ;
2011-03-28 07:08:18 +00:00
#print Dumper($sn);
2011-03-28 06:57:08 +00:00
if ( keys ( %$ sn ) == 0 ) {
my $ reqcopy = { %$ req } ;
push @ requests , $ reqcopy ;
}
2011-03-25 06:39:06 +00:00
# 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" ) ;
2011-03-28 06:57:08 +00:00
if ( ! GetOptions ( \ % opt , qw( h|help v|version V|verbose c=s f=s o ) ) ) {
2011-03-25 06:39:06 +00:00
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 ;
}
2012-04-28 09:25:12 +00:00
2011-12-08 07:17:50 +00:00
my ( $ current_ppc_ent ) = $ ppctab - > getNodeAttribs ( $ current_node , @ ppcattribs ) ;
my ( $ fip_ppc_ent ) = $ ppctab - > getNodeAttribs ( $ fip_node , @ ppcattribs ) ;
2011-03-25 06:39:06 +00:00
my @ current_attrs ;
my @ fip_attrs ;
my $ cec ;
if ( $ current_ppc_ent - > { 'parent' } eq $ fip_ppc_ent - > { 'parent' } ) {
2012-04-28 09:25:12 +00:00
my % tabs ;
$ tabs { ppc } = $ ppctab ;
$ tabs { vpd } = xCAT::Table - > new ( 'vpd' , - create = > 1 , - autocommit = > 0 ) ;
unless ( ! exists ( $ tabs { vpd } ) ) {
$ rsp - > { data } - > [ 0 ] = "Cannot open vpd table" ;
xCAT::MsgUtils - > message ( "E" , $ rsp , $ callback ) ;
return 1 ;
}
xCAT::FSPUtils:: getHcpAttribs ( $ request , \ % tabs ) ;
2011-03-25 06:39:06 +00:00
#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" ;
2012-04-28 09:25:12 +00:00
my $ values = xCAT::FSPUtils:: fsp_state_action ( $ request , $ cec , \ @ current_attrs , $ action ) ;
2011-03-25 06:39:06 +00:00
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 ) ;
2011-03-28 06:57:08 +00:00
if ( ! ( exists ( $ opt - > { o } ) ) ) {
$ keyhash { 'node' } = $ fip_node ;
$ ppctab - > setAttribs ( \ % keyhash , $ current_ppc_ent ) ;
}
2011-03-25 06:39:06 +00:00
$ 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 ;
}
2011-12-08 07:17:50 +00:00
my $ current_ent = $ nodepostab - > getNodeAttribs ( $ current_node , @ nodeposattribs ) ;
my $ fip_ent = $ nodepostab - > getNodeAttribs ( $ fip_node , @ nodeposattribs ) ;
2011-03-25 06:39:06 +00:00
# swap the current ent and the fip ent
$ keyhash { 'node' } = $ current_node ;
$ nodepostab - > setAttribs ( \ % keyhash , $ fip_ent ) ;
2011-03-28 06:57:08 +00:00
if ( ! ( exists ( $ opt - > { o } ) ) ) {
$ keyhash { 'node' } = $ fip_node ;
$ nodepostab - > setAttribs ( \ % keyhash , $ current_ent ) ;
}
2011-03-25 06:39:06 +00:00
$ 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" ;
2012-04-28 09:25:12 +00:00
$ values = xCAT::FSPUtils:: fsp_api_action ( $ request , $ cec , \ @ current_attrs , $ action ) ;
2011-03-25 06:39:06 +00:00
#$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' } ) {
2012-04-28 09:25:12 +00:00
$ vals = xCAT::FSPUtils:: fsp_api_action ( $ request , $ fip_node , \ @ fip_attrs , $ action , $ tooltype , $ drc_index ) ;
2011-03-25 06:39:06 +00:00
$ 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" ;
2011-03-28 06:57:08 +00:00
$ rsp - > { data } - > [ 2 ] = " swapnodes -c current_node -f fip_node [-o]" ;
2011-03-25 06:39:06 +00:00
xCAT::MsgUtils - > message ( "I" , $ rsp , $ callback ) ;
return 0 ;
}
1 ;